React Native and Firebase
If you are in to mobile development, you might have heard about React Native. With the help of React Native, you can build mobile applications for both Android and iOS with a single code base. Sounds cool huh? Without wasting much time, let's jump right into our project.
In this tutorial, we will build a React Native app that uses Firebase Authentication with email and password. For those of you wanna know more about Firebase and the different services they provide, check out there official site.
I'm assuming you have some basic JavaScript or React Native experience and I've made the code as simple as possible.
So let's begin 😊
What we are gonna build
In this tutorial, we are gonna be building a simple React Native app with Firebase user authentication.
We will create user interfaces for app Splash screen, Sign Up screen, Login screen and finally a simple Home screen. To keep the whole application simple, I left the user input validation functionalities. let's get started.
If you want to add input field validations to the application, you can simply add those validations to the corresponding touch input functions.
Let's get started!
Create a Project in Firebase
To create a project in Firebase, head over to Firebase console. To create a firebase project, click 'Add Project', type in your project's name and select your region, hit 'Create Project'. The firebase will take care of the rest 😉.
Once project is created, now we need to enable the 'Email Authentication' within firebase.
Now we need to let the firebase know about our project. so, to complete the installation, we will do these steps for Android and will follow these steps for iOS
Create a React Native project
In this tutorial, we will be using React Native cli to build our project. Check this link, if you need help installing React Native cli to your computer.
react-native init FirebaseAuthentication
This will walk you through your project initialization. once completed, now we have to install the required dependencies to our project. As of now, I'm not gonna go into redux to keep the post as simple as possible.
npm install react-native-firebase react-navigation --save
Once installation is completed, we have to link these libraries to our project.
react-native link
Now we have the basic project setup complete, let's take a look at the project structure.
Inside the project root folder, we have an index file which we will use as the project/application entry point. We will keep all our application related code inside 'app/src' folder. Then we will divide the project screens into different modules such as Splash screen, Sign Up screen, Login screen, Home screen.We will also have a 'router.js' file, which will keep the application navigation flow.
Uh oh, we almost forgot one important step, before getting our hands into coding part, we still gotta enable/install/add the firebase authentication service to our project. To do so, follow these steps for iOS and follow these steps for Android .
Let's start the coding 🤪
As I was saying, the 'index.js' file is our application entry point. so, let's start from the index file itself.
index.js
import React from 'react';
import React from 'react';
import { AppRegistry } from 'react-native';
import { name as appName } from './app.json';
import { ScreenRegistry } from './app/src/router';
const FirebaseAuthentication = () => (
<ScreenRegistry />
)
AppRegistry.registerComponent(appName, () => FirebaseAuthentication);
In the index file, we have imported our router file, which we will create in a minute, and specified it as the main navigation file. We will import all our application specific files inside the 'router.js' file.
app/src/router.js
import React, {component} from 'react'
import { createStackNavigator,createSwitchNavigator } from 'react-navigation';
import Splash from './modules/splash/splash'
import SignUp from './modules/signup/signup'
import Login from './modules/login/login'
import Home from './modules/home/home'
const Authentication = createStackNavigator({
Login: {screen: Login},
SignUp: {screen: SignUp}
})
const ApplicationHome = createStackNavigator({
Home: {screen: Home}
})
export const ScreenRegistry = createSwitchNavigator({
Splash: {screen: Splash},
Authentication: {screen: Authentication},
ApplicationHome: {screen: ApplicationHome}
}
,{
initialRouteName: 'Splash'
}
);
we have divided our project into different stacks and then all the stacks are put together with the help of a switch navigator. The stack navigator, switch navigator etc. do help a lot in defining navigational flow of our application. Check this link to read more about the React Navigation.
Now let's start creating our user interface.
app/src/modules/splash/splash.js
import React, { Component } from 'react';
import {
StatusBar,
Platform,
StyleSheet,
Text,
View,
ActivityIndicator
} from 'react-native';
export default class Splash extends Component {
render() {
return (
<View style={styles.container}>
<StatusBar
backgroundColor={'transparent'}
barStyle="dark-content"
/>
<Text style={styles.text}>Firebase Authentication</Text>
<ActivityIndicator size="large" color="#8e44ad" />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#FFFFFF',
},
text: {
fontSize: 20,
textAlign: 'center',
margin: 10,
color: '#000000'
}
});
app/src/modules/signup/signup.js
import React, { Component } from 'react';
import {
Platform,
StyleSheet,
Text,
View,
TextInput,
TouchableOpacity,
Dimensions,
StatusBar
} from 'react-native';
const { width, height } = Dimensions.get('window');
export default class Signup extends Component {
constructor(props) {
super(props);
this.state = {
email: '',
password: ''
};
}
static navigationOptions = ({ navigation }) => ({
header: null
})
signupUser() {
//will cover later
console.log('Sign up user')
}
render() {
return (
<View style={styles.container}>
<StatusBar
backgroundColor={'transparent'}
barStyle={'dark-content'}
/>
<Text style={styles.text}>Sign Up</Text>
<TextInput
onChangeText={(email) => this.setState({ email })}
placeholder={'email'}
underlineColorAndroid='#ecf0f1'
placeholderTextColor='#b2bec3'
value={this.state.email}
multiline={false}
style={styles.input}
/>
<TextInput
onChangeText={(password) => this.setState({ password })}
placeholder={'password'}
secureTextEntry={true}
underlineColorAndroid='#ecf0f1'
placeholderTextColor='#b2bec3'
value={this.state.password}
multiline={false}
style={styles.input}
/>
<TouchableOpacity style={[styles.button]}
activeOpacity={0.7}
onPress={() => this.signupUser(this.state.email, this.state.password)}
>
<Text style={styles.buttonText}>Sign Up</Text>
</TouchableOpacity>
<View style={styles.loginView}>
<Text style={styles.info}>Already have an account?</Text>
<TouchableOpacity
activeOpacity={0.7}
onPress={() => this.props.navigation.navigate('Login')}
>
<Text style={styles.loginlink}>Login</Text>
</TouchableOpacity>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#FFFFFF',
},
text: {
fontSize: width / 18,
textAlign: 'center',
margin: 10,
color: '#8e44ad',
fontWeight: 'bold'
},
input: {
paddingLeft: 18,
width: width - 50,
textAlign: 'justify',
marginTop: width * 0.08
},
button: {
marginTop: 25,
width: width - 50,
height: width * 0.12,
backgroundColor: "#8e44ad",
alignItems: 'center',
justifyContent: 'center',
borderRadius: 10,
},
buttonText: {
fontSize: width / 23,
fontWeight: '400',
color: 'white'
},
loginView: {
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
marginTop: 15
},
info: {
fontSize: width / 24,
textAlign: 'center',
margin: 10,
},
loginlink: {
fontSize: width / 22,
margin: 10,
color: '#8e44ad',
fontWeight: '300'
}
});
app/src/modules/login/login.js
import React, { Component } from 'react';
import {
Platform,
StyleSheet,
Text,
View,
TextInput,
TouchableOpacity,
Dimensions,
StatusBar
} from 'react-native';
const { width, height } = Dimensions.get('window');
export default class Login extends Component {
constructor(props) {
super(props);
this.state = {
email: '',
password: ''
};
}
static navigationOptions = ({ navigation }) => ({
header: null
})
loginUser() {
//will cover later
console.log('login user')
}
render() {
return (
<View style={styles.container}>
<StatusBar
backgroundColor={'transparent'}
barStyle={'dark-content'}
/>
<Text style={styles.text}>Login</Text>
<TextInput
onChangeText={(email) => this.setState({ email })}
placeholder={'email'}
underlineColorAndroid='#ecf0f1'
placeholderTextColor='#b2bec3'
value={this.state.email}
multiline={false}
style={styles.input}
/>
<TextInput
onChangeText={(password) => this.setState({ password })}
placeholder={'password'}
secureTextEntry={true}
underlineColorAndroid='#ecf0f1'
placeholderTextColor='#b2bec3'
value={this.state.password}
multiline={false}
style={styles.input}
/>
<TouchableOpacity style={[styles.button]}
activeOpacity={0.7}
onPress={() => this.loginUser(this.state.email, this.state.password)}
>
<Text style={styles.buttonText}>Login</Text>
</TouchableOpacity>
<View style={styles.loginView}>
<Text style={styles.info}>Don't have an account?</Text>
<TouchableOpacity
activeOpacity={0.7}
onPress={() => this.props.navigation.navigate('SignUp')}
>
<Text style={styles.loginlink}>Sign Up</Text>
</TouchableOpacity>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#FFFFFF',
},
text: {
fontSize: width / 18,
textAlign: 'center',
margin: 10,
color: '#8e44ad',
fontWeight: 'bold'
},
input: {
paddingLeft: 18,
width: width - 50,
textAlign: 'justify',
marginTop: width * 0.08
},
button: {
marginTop: 25,
width: width - 50,
height: width * 0.12,
backgroundColor: "#8e44ad",
alignItems: 'center',
justifyContent: 'center',
borderRadius: 10,
},
buttonText: {
fontSize: width / 23,
fontWeight: '400',
color: 'white'
},
loginView: {
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
marginTop: 15
},
info: {
fontSize: width / 24,
textAlign: 'center',
margin: 10,
},
loginlink: {
fontSize: width / 22,
margin: 10,
color: '#8e44ad',
fontWeight: '300'
}
});
app/src/modules/home/home.js
import React, {Component} from 'react';
import {
Platform,
StyleSheet,
Text,
View,
TouchableOpacity,
Dimensions,
StatusBar
} from 'react-native';
const { width, height } = Dimensions.get('window');
export default class Home extends Component{
constructor(props) {
super(props);
this.state = {
username: '',
};
}
signoutuser(){
//will cover later
console.log('user signed out')
}
render() {
const { username} = this.state
return (
<View style={styles.container}>
<StatusBar
backgroundColor={'transparent'}
barStyle={'dark-content'}
/>
<Text style={styles.welcome}>Hi {username}</Text>
<TouchableOpacity style={[styles.button]}
activeOpacity={0.7}
onPress={() => this.signoutuser()}
>
<Text style={styles.buttonText}>Sign Out</Text>
</TouchableOpacity>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
button: {
marginTop: 25,
width: width - 50,
height: width * 0.12,
backgroundColor: "#8e44ad",
alignItems: 'center',
justifyContent: 'center',
borderRadius: 10,
},
buttonText: {
fontSize: width / 23,
fontWeight: '400',
color: 'white'
},
});
If we run our app now, we will see the loading screen spinning forever. Don't worry, everything is working as expected till now.
Now we need to determine whether a user is logged in or not and based on that, we need to route the user to login/signup or the application home page.If the user is already logged in, we will route them to the Home screen, and if not, we will route them to the login/signup page.
Check if a user is already logged in
We can perform the user authentication check in the splash.js file. we can use firebase to determine the authentication state of a user. Let's add a few more line to the splash.js file.
Hang on....we are almost there 😌
add the following lines to 'app/src/modules/splash/splash.js'
import firebase from 'react-native-firebase';
componentDidMount() {
firebase.auth().onAuthStateChanged(user => {
this.props.navigation.navigate(user ? 'ApplicationHome' : 'Authentication')
})
}
we are using firebase's onAuthStateChanged listener to get the current auth state of the user. If they are already authenticated with the firebase server, we will route directly to our application's home screen and if not, we will route them to the login screen.
Since, we haven't authenticated any user with the firebase server yet, we should be navigated to the login screen automatically.
Sign Up a user
To sign up a user, we are going to add a definition to the signupUser() in our signup.js file.
add the following lines to the 'app/src/modules/signup/signup.js'
import firebase from 'react-native-firebase';
signupUser(email, password) {
firebase
.auth().createUserWithEmailAndPassword(email, password)
.then(() => this.props.navigation.navigate('ApplicationHome'))
.catch(error => this.setState({ errorMessage: error.message }))
}
The signupUser() uses the firebase's createUserWithEmailAndPassword function to register the user with the given username and password. Then the user is redirected to the application home screen.
Display current user on the home screen
To display the current user in the application home screen, we will add the following function to the 'app/src/modules/home/home.js' file
componentDidMount() {
this.setState({ username:firebase.auth().currentuser.email})
}
Now when we see our home screen, we should see the user's email address displayed in our home screen.
Logging a user in
Now that we have a registered user set up, let's see how to log in a user once a user account is created.
add these line to the 'app/src/modules/login/login.js' file.
import firebase from 'react-native-firebase';
loginUser(email, password) {
firebase
.auth()
.signInWithEmailAndPassword(email, password)
.then(() => this.props.navigation.navigate('ApplicationHome'))
.catch(error => this.setState({ errorMessage: error.message }))
}
Sign out a user
Now the last step, sign out a user. let's jump to 'app/src/modules/home/home.js' and add a few more lines.
import firebase from 'react-native-firebase';
signoutuser() {
firebase.auth().signOut()
.then(() => this.props.navigation.navigate('Authentication'))
.catch(error => this.setState({ errorMessage: error.message }))
}
Awesome huh?😎
If you enjoyed coding with me, feel free to checkout the Github repo as well and stay tuned for more.
Kudos 🥂
U r a great developer
ReplyDelete