How to save login state locally with Context API & AsyncStorage on React Native

React JavaScript by React

Before we start this, make sure you know about React Hooks or familiar with Functional Component. In this post, we will look how can the login state be saved locally in the app. The same logic can be extended to other functions as well (and not just limited to login).

Why save locally?

You may not want your app’s user to login every time on launching the app. That would be cumbersome. There should be some mechanism to “remember” their situation (logged in: true or false).

Depending on what the status is you can choose to show some app screens (like a profile page, content page) and skip others (like login page, sign up page).

How about Redux?

Redux can only maintain the state till the app is “on”. If the user exits the app, or say, for example, reboots the phone or the app crashes the state resets.

Here’s some flow of how you do it with Redux

Redux login flow
Redux login flow
React Redux flow

And why you choose Context?

Context provides a way to pass data through the component tree without having to pass props down manually at every level

Here’s the flow of how you do it with Context

E.g Context flow
E.g Context flow
React Context flow

How we do it?

Install the AsyncStorage on your project
Go in your project directory (where your package.json exists) and:

  • For yarn users run yarn add @react-native-community/async-storage
  • For npm users run npm i @react-native-community/async-storage

Post-installation, if you use React Native version <= 0.59 you also need to link it by running: react-native link @react-native-community/async-storage

If it seems unclear you can check the documentation here

Here’s the code!

First of all, we need setup Context API first

Importing Context API in React

Creates a Context object. When React renders a component that subscribes to this Context object it will read the current context value from the closest matching Provider above it in the tree.

After that, you need to create 1 file called the AuthNavigator
You can read more here

https://reactnavigation.org/

This file used to navigate after the Context was called / where you want to go

NOTE: AsyncStorage can only store string data, so in order to store object data you need to serialize it first. For data that can be serialized to JSON you can use JSON.stringify() when saving the data and JSON.parse() when loading the data.

Context defines 2 types, called Provider and Consumer, which Provider mean it serves the state globally, and then Consumer (which will consume your state, I will define it later)

As you can see now, we already create the Context and the Context Navigator!
and then you need to create a login function that connected to your API

function signInHome() {         setIsLoading(true);         setModalVisible(true);loginClient.post(‘/openid-connect/token’,  qs.stringify(requestBody)).then((response) => {       setIsLoading(false);       setModalVisible(false);       signIn(response.data.access_token)}).catch(onFailure);}const onFailure = error => {     console.log(`error: ${JSON.stringify(error.response)}`);     setIsLoading(false);     setModalTitle(‘Error’);     setModalVisible(true);};

On that code we already defined the onPress login function, don't forget to define your render component

return (<AuthContext.Consumer>     {({ signIn }) => (         <View>          <Button            status="control"            size="medium"            status="primary"            onPress={() => signInHome(signIn)}          > Login </Button>         </View></AuthContext.Consumer>);

That's the consumer I said before, you might questioning right now, why I write signIn. It, because I need to consume what state that I write globally in

AuthNavigator.js

or simply we can say like Youtube, subscribe and unsubscribe

Le Felina, call your stored token

Some of you might ask, how we provide/subscribe the token that we already stored locally and call it with API that we already defined?
Here’s the cookbook!

First, you need to import useAsyncStorage to your services

import { useAsyncStorage } from '@react-native-community/async-storage';

set some state to define what kind of call you want

const { getItem } = useAsyncStorage('userToken')
// note : if you set 2 token , such as refresh_token or access_token, you can define like
useAsyncStorage(['userToken','userRefreshToken'])const [value, setValue] = useState([])function readItemFromStorage = async () => { const item = await getItem(); //some log to makesure your token is called console.log('User Token', item) setValue(item);}//it depends on how you call it

And that’s it! Simple and easy to understand. The login state object will now be stored locally on the device and will persist even after the app is closed / the device reboots. It’s just like an app-specific DB.

In summary, Context API is very useful if you want to avoid props drilling in React, it will help your teammates to read your code more clearly and cleaner.

Hope this was helpful!

References :

Software Engineer who got D score in Introduction to Programming at college 👨‍🎓🧑‍💻