How Authentication Flow works in React Native apps using React Navigation 4.x
Mobile apps are made of screens that in number can vary depending on the app you are developing. Handling user navigation can be tricky to learn and do in mobile apps, but with dedicated open-source libraries like react-navigation
do make the process a lot easier.
React Navigation library is common among React Native developers. It is built with JavaScript, and you can create React components and apply any navigation pattern. On the device, it will give the natural look and feel.
It is up to the developer now, on how to make the best use of navigation between different screens in a React Native app. There are more than one navigation patterns available. If you are starting in the React Native ecosystem, this post will guide you through to use different the patterns of navigation such as Stack and Switch navigation using react-navigation
library's latest 4.x.x
version.
Table of Contents
🔗- Requirements
- Installing navigation library
- Create app screens
- Setup navigation
- Navigating between two screens
- Managing authentication flow
- Conclusion
Requirements
🔗If you are going to code along, make sure you have already installed the following:
- Nodejs (>=
10.x.x
) with npm/yarn installed. - expo-cli (>=
3.x.x
), previously known ascreate-react-native-app
. - Mac users must be running an iOS simulator.
- Windows/Linux users must be running an Android emulator.
To know more about how to setup and run the simulator or the emulator on your local development environment visit React Native’s official documentation here.
Installing navigation library
🔗To get started, create a new Expo app using expo-cli
with the following command from a terminal window. When asked, choose the blank
template.
expo init expo-example# navigate inside the project directorycd expo-example
Once inside the project directory, install the following dependencies.
yarn add react-navigation react-navigation-stackexpo install react-native-gesture-handlerreact-native-screens
As compared to previous versions of react-navigation
, all three navigation patterns have been modularised in their own dependencies. If you are using:
- stack navigation, then install
react-navigation-stack
- for tabs install
react-navigation-tabs
- for drawer install
react-navigation-drawer
- switch navigation pattern is still under
react-navigation
and is only used for specific use cases such as authentication flow
More appropriate information about each dependency related to its own navigation pattern can be found in the official docs here.
After installing these dependencies, you can verify that they have been installed by opening the package.json
file.
1"dependencies": {2 "expo": "^34.0.1",3 "react": "16.8.3",4 "react-dom": "^16.8.6",5 "react-native": "https://github.com/expo/react-native/archive/sdk-34.0.0.tar.gz",6 "react-native-gesture-handler": "~1.3.0",7 "react-native-reanimated": "~1.1.0",8 "react-native-screens": "1.0.0-alpha.22",9 "react-native-web": "^0.11.4",10 "react-navigation": "4.0.0",11 "react-navigation-stack": "1.5.1"12 },
Create App Screens
🔗I like to arrange different setups and related files under the folder structure. Here is how it is going to look like at the end of this tutorial. It is also a good practice to organize or give structure to your project.
The three files inside the screens
folder are going to be functional components for now, with some dummy text to display. Create these files with the following code snippets.
For Home.js
:
1import React from 'react';2import { StyleSheet, Text, View } from 'react-native';34export default function Home() {5 return (6 <View style={styles.container}>7 <Text>Home</Text>8 </View>9 );10}1112const styles = StyleSheet.create({13 container: {14 flex: 1,15 backgroundColor: '#fff',16 alignItems: 'center',17 justifyContent: 'center'18 }19});
For Login.js
:
1import React from 'react';2import { StyleSheet, Text, View } from 'react-native';34export default function Login() {5 return (6 <View style={styles.container}>7 <Text>Login</Text>8 </View>9 );10}1112const styles = StyleSheet.create({13 container: {14 flex: 1,15 backgroundColor: '#fff',16 alignItems: 'center',17 justifyContent: 'center'18 }19});
For Signup.js
:
1import React from 'react';2import { StyleSheet, Text, View } from 'react-native';34export default function Signup() {5 return (6 <View style={styles.container}>7 <Text>Signup</Text>8 </View>9 );10}1112const styles = StyleSheet.create({13 container: {14 flex: 1,15 backgroundColor: '#fff',16 alignItems: 'center',17 justifyContent: 'center'18 }19});
The idea here is to create a foundation of three different screens and mock a login/signup and main (in the current case, the home screen) screen navigation pattern. This is a common pattern in most mobile apps where the user has to either signup or login before accessing the rest of the application.
Setup Navigation
🔗After creating these three screens, create a new directory called navigation
. Inside this, create three new files:
index.js
AppNavigation.js
AuthNavigation.js
Let us setup the AppNavigation
first since it will contain only one screen. Open up the file and add the following code.
1//AppNavigation.js2import { createStackNavigator } from 'react-navigation-stack';3import Home from '../screens/Home';45const AppNavigation = createStackNavigator(6 {7 Home: { screen: Home }8 },9 {10 initialRouteName: 'Home'11 }12);1314export default AppNavigation;
Stack Navigation provides your app to navigate between screens, where each new screen is placed on the top of the previous one. It is literally like a stack and hence the name. This is done by createStackNavigator
function. A route configuration object is passed to this function. The Home
route corresponds to the Home.js
component.
On an iOS device, a new screen slides from the right, and on Android, it fades from the bottom.
Next, edit AuthNavigation.js
file.
1//AuthNavigation.js2import { createStackNavigator } from 'react-navigation-stack';3import Login from '../screens/Login';4import Signup from '../screens/Signup';56const AuthNavigation = createStackNavigator(7 {8 Login: { screen: Login },9 Signup: { screen: Signup }10 },11 {12 initialRouteName: 'Login'13 }14);1516export default AuthNavigation;
Similarly, in AuthNavigation
two screens, login and signup are passed. In the second object that is passed to createStackNavigator
function, the initialRouteName
indicates that when this navigation file runs, the first screen that will be shown is going to be Login
. In other words, it is used to set a default screen to whatever the value initialRouteName
is set to.
In AppNavigation
since there is only one screen, so it will always show Home
screen whether to pass the initialRouteName
in that file or not. Next, open index.js
file in the same directory and add the following code.
1//index.js2import { createAppContainer } from 'react-navigation';3import AuthNavigation from './AuthNavigation';45const AppContainer = createAppContainer(AuthNavigation);67export default AppContainer;
The createAppContainer
function is responsible for managing the navigation state of the app and links the app to the top-level navigator. The navigation state comes in handy when you are passing data between two screens.
Lastly, open the App.js
file and use AppContainer
to be the top-level component.
1//App.js2import React from 'react';3import AppContainer from './navigation';45export default function App() {6 return <AppContainer />;7}
Now open your app in a simulator device by executing the command expo start
from a terminal window. You will see that it shows only the Login
screen.
Notice the empty space at the top of the screen? That is the header section. When using Stack Navigation pattern, each screen is assigned a header automatically. If you do not require to use it, you can set the headerMode
property to the value of none
to createStackNavigator
function. Open AuthNavigation.js
to edit.
1// AuthNavigation.js2const AuthNavigation = createStackNavigator(3 {4 Login: { screen: Login },5 Signup: { screen: Signup }6 },7 {8 initialRouteName: 'Login',9 headerMode: 'none'10 }11);
You can read more about app containers here.
Navigating between two screens
🔗Right now, there is no way you can navigate from the Login
to the Signup
screen. To do so, let us use this.props.navigation
. Each screen component in the app using react-navigation
library is automatically provided with the navigation
prop. It further has different reference values to navigate between different screens directly from a screen.
To transit between login to signup, create a button like below and pass an onPress
prop to it in Login.js
file. The value of this prop is going to hold the navigation
prop reference.
1//Login.js23//import Button4import { StyleSheet, Text, View, Button } from 'react-native';56export default class Login extends React.Component {7 render() {8 return (9 <View style={styles.container}>10 <Text>Login</Text>11 <Button12 title="Go to Signup"13 onPress={() => this.props.navigation.navigate('Signup')}14 />15 </View>16 );17 }18}
Passing the name of the route as the first parameter to navigation.navigate()
is necessary. Now go back to the simulator, and you will find a new button. Press the button, and it will take you to the Signup
screen component.
Similarly, you can add a way to navigate back to the login screen component from the signup.
1//Signup.js23export default class Signup extends React.Component {4 goToLogin = () => this.props.navigation.navigate('Login');5 render() {6 return (7 <View style={styles.container}>8 <Text>Signup</Text>9 <Button title="Go to Login" onPress={this.goToLogin} />10 </View>11 );12 }13}
Here is the output.
Managing Authentication Flow
🔗In React Navigation, to manage authentication flow, Switch Navigator is used. This navigation pattern only loads one screen at a time, and there is no back functionality by default. It resets the initial route when switching between the screens. To get started open index.js
file, import createSwitchNavigator
from react-navigation
and add the following code.
1//index.js2import { createSwitchNavigator, createAppContainer } from 'react-navigation';3import AuthNavigation from './AuthNavigation';4import AppNavigation from './AppNavigation';56const SwitchNavigator = createSwitchNavigator(7 {8 Auth: AuthNavigation,9 App: AppNavigation10 },11 {12 initialRouteName: 'Auth'13 }14);1516const AppContainer = createAppContainer(SwitchNavigator);1718export default AppContainer;
Note that, the AppContainer
is still being exported from the file, but it now accepts SwitchNavigator
as the parameter. Like the createStackNavigator
, createSwitchNavigator
also accepts route config as the first parameter and the configuration values as the second. The route config is going to be done between the authentication navigation screens and the other screens related to the app.
Import both AuthNavigation
and AppNavigation
and set the Auth
as the initial route. This means that the login screen is going to be shown for the when apps load for the first time.
Let us mock the behavior of logging into the app and see what happens when the user successfully logs in. Open Login.js
file, define an initial state with two properties: email
and password
.
1//Login.js2import React from 'react';3import { StyleSheet, View, Button, TextInput } from 'react-native';45export default class Login extends React.Component {6 state = {7 email: '',8 password: ''9 };1011 handleEmailChange = email => {12 this.setState({ email });13 };1415 handlePasswordChange = password => {16 this.setState({ password });17 };1819 onLogin = async () => {20 const { email, password } = this.state;21 try {22 if (email.length > 0 && password.length > 0) {23 this.props.navigation.navigate('App');24 }25 } catch (error) {26 alert(error);27 }28 };2930 goToSignup = () => this.props.navigation.navigate('Signup');31 render() {32 const { email, password } = this.state;3334 return (35 <View style={styles.container}>36 <View style={{ margin: 10 }}>37 <TextInput38 name="email"39 value={email}40 placeholder="Enter email"41 autoCapitalize="none"42 onChangeText={this.handleEmailChange}43 />44 </View>45 <View style={{ margin: 10 }}>46 <TextInput47 name="password"48 value={password}49 placeholder="Enter password"50 secureTextEntry51 onChangeText={this.handlePasswordChange}52 />53 </View>54 <Button title="Login" onPress={this.onLogin} />55 <Button title="Go to Signup" onPress={this.goToSignup} />56 </View>57 );58 }59}6061const styles = StyleSheet.create({62 container: {63 flex: 1,64 backgroundColor: '#fff',65 alignItems: 'center',66 justifyContent: 'center'67 }68});
The onLogin
handler function allows the user to navigate to the Home
screen only if the email and the password fields are not empty. It is used on the onPress
prop for the following button.
1<Button title="Login" onPress={this.onLogin} />
Look at the complete demo below.
Conclusion
🔗The authentication flow works! By following this tutorial, you have learned how to use the latest react-navigation
library to manage and mimic an authentication flow in a React Native app. Using the current knowledge, in the next post, you are going to build some actual forms in React Native apps with proper styling and validation using awesome libraries like Formik and Yup. I hope this post works as fundamental for the next one.
You can find the complete code used in this tutorial at the Github repo here.
Important resources from this post:
Originally published at Heartbeat
More Posts
Browse all posts