How to save login state locally using AsyncStorage & Redux in React Native
Tags: tutorial, beginners, reactnative, javascript
Published: 2020-06-21 08:08:18

In the last post (here: https://dev.to/skd1993/creating-a-simple-login-function-with-redux-and-thunk-in-react-native-33ib) I discussed the steps to create a simple login logic using Redux and Thunk in React Native.

Continuing from there, in this post, we will look at 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 you app's user to login everytime 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 profile page, content page) and skip others (like login page, sign up page).

## What about Redux?

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

## How can we do it?

Simply by maintaining a copy of your redux state locally on the device. We can `AsyncStorage` library to achieve this. It will allow us to store JSON object in local storage.

Let's have a look at the steps now.

### Install the `AsyncStorage` library
Go in your project directory (where your `package.json` exists) and:
* For **npm** users run `npm i @react-native-community/async-storage`
* For **yarn** users run `yarn add @react-native-community/async-storage`

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

### Reminder on Redux...
As discussed in the previous post, for sake of simplicity, all redux code is placed in a 'redux' folder, while the components are in 'src/components/&lt; ComponentName &gt;/index.js'.

This is how our redux folder looks like.  

redux
├── actions.js
├── actionTypes.js
├── initialState.js
├── reducer.js
└── store.js

We currently have the following `login` function to call the login API, and get back the data (in `actions.js`)

```js
import { Alert } from 'react-native'; // to show alerts in app

export const login = (loginInput) => {
  const { username, password } = loginInput;
  return (dispatch) => {  // don't forget to use dispatch here!
    return fetch(LoginUrl, {
      method: 'POST',
      headers: {  // these could be different for your API call
        Accept: 'application/json',
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(loginInput),
    })
      .then((response) => response.json())
      .then((json) => {
        if (json.msg === 'success') { // response success checking logic could differ
          dispatch(setLoginState({ ...json, userId: username })); // our action is called here
        } else {
          Alert.alert('Login Failed', 'Username or Password is incorrect');
        }
      })
      .catch((err) => {
        Alert.alert('Login Failed', 'Some error occured, please retry');
        console.log(err);
      });
  };
};
```

To start using `AsyncStorage` let's import it first: 
```js
import AsyncStorage from '@react-native-community/async-storage';
```

The let us tweak the `response` part a bit to simplify:
```js
if (json.msg === 'success') { // response success checking logic could differ
  const o = { ...json, userId: username };
  setLoginLocal(o); // storing in local storage for next launch
  dispatch(setLoginState(o)); // our action is called here
}
```        

As you can see, now `setLoginLocal` function will take the data and be responsible for local storage. Same data is passed in the next line to our action dispatcher.

Let's create the `setLoginLocal` function now in the same file.

```js
const setLoginLocal = async (loginData) => {
  try {
    await AsyncStorage.setItem('loginData', JSON.stringify(loginData));
  } catch (err) {
    console.log(err);
  }
};
```

**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.

> `setItem()` is used both to add new data item (when no data for given key exists), and to modify exiting item (when previous data for given key exists).

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 app is closed / device reboots. It's just like an app-specific DB.

You can read more about the library here:
* https://www.npmjs.com/package/@react-native-community/async-storage
* https://react-native-community.github.io/async-storage/docs/install

In the coming posts, we will look at how to utilize this local state while loading the app on launch.

Hope this was helpful 😄