DEV Community

Cover image for How to save login state locally using AsyncStorage & Redux in React Native
Shobhit Kumar
Shobhit Kumar

Posted on

How to save login state locally using AsyncStorage & Redux in React Native

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/< ComponentName >/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)

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);
      });
  };
};
Enter fullscreen mode Exit fullscreen mode

To start using AsyncStorage let's import it first:

import AsyncStorage from '@react-native-community/async-storage';
Enter fullscreen mode Exit fullscreen mode

The let us tweak the response part a bit to simplify:

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
}
Enter fullscreen mode Exit fullscreen mode

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.

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

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:

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

Hope this was helpful 😄

Top comments (0)