AsyncStorage in React Native and how to use it with app state manager

AsyncStorage is React Native’s API for storing data persistently over the device. It’s a storage system that developers can use and save data in the form of key-value pairs. If you are coming from a web developer background, it resembles a lot like localStorage browser API.

AsyncStorage API is asynchronous, so each of its methods returns a Promise object and in case of error, an Error object. It’s also global, so use it with caution.

Why use AsyncStorage?

AsyncStorage can prove very helpful when we want to save data that the application would need to use, even when the user has closed it or has even closed the device. It is not a replacement for state data and it should not be confused with that; besides, state data will be erased from memory when the app closes.

A typical example of that, is the data that the app will need to login the user, like session id and/or user id. The app will need these data to be saved permanently over the device.

It is recommended that you use an abstraction on top of AsyncStorage instead of AsyncStorage directly

Simple usage

Importing the AsyncStorage library:

import { AsyncStorage } from "react-native"

Here, it suggests not to use AsyncStorage object directly, but instead use the API methods that are designed for this purpose — exactly as we are supposed to do with React’s class components and the state object / methods.

The basic actions to perform in AsyncStorage are:

  1. set an item, along with its value
  2. retrieve an item’s value
  3. remove an item 

Save to AsyncStorage

Let’s set a new key called userId along with its value:

const userId = '8ba790f3-5acd-4a08-bc6a-97a36c124f29';
const saveUserId = async userId => {
  try {
    await AsyncStorage.setItem('userId', userId);
  } catch (error) {
    // Error retrieving data
    console.log(error.message);
  }
};

Simple as that we save GUID value to userId key with the use of async/await promise API (or .then if you prefer).

Retrieve value from AsyncStorage

If we want to retrieve the value from previous example we do it like that:

const getUserId = async () => {
  let userId = '';
  try {
    userId = await AsyncStorage.getItem('userId') || 'none';
  } catch (error) {
    // Error retrieving data
    console.log(error.message);
  }
  return userId;
}

In this case, we only need the string key to refer to the AsyncStorage needed item. In case userId key does not exist in AsyncStorage (i.e. the first time the app loads), the function will return undefined or in the example above the string 'none'.

Delete from AsyncStorage

If we want to completely delete the reference key and its value set in previous example (i.e. we do a major change in our app and our login process changes) we do it like that:

const deleteUserId = async () => {
  try {
    await AsyncStorage.removeItem('userId');
  } catch (error) {
    // Error retrieving data
    console.log(error.message);
  }
}

Usage with state manager

When we use a state manager within our apps (i.e. Redux — or new React’s context API), it is a really good idea to abstract the related AsyncStorage code within the state manager code, instead of “overloading” the screen’s component code.

To understand what this means and how to achieve that, let’s assume our example from before; saving user’s id along with user’s session id this time. User and session id should be saved from the app during the registration process.

Example with Redux

Assuming that we have Redux configured along with a User reducer, and a SAVE_USER action, then the app will dispatch this action during user registration to save the new user data within the state. So instead of writing the extra code within the Register component, we can do that inside the User reducer.

In app/reducers/user.js we will have the following code:

// packages
import {AsyncStorage} from 'react-native';
const initialState = {
  id: null,
  sessionId: null,
  username: null,
  password: null
};
export default (state = initialState, action) => {
  switch (action.type) {
    case 'SAVE_USER':
      // save sessionId & userId in AsyncStorage
      if (action.user.sessionId) {
        AsyncStorage.setItem('sessionId', action.user.sessionId);
      }
      if (action.user.id) {
        AsyncStorage.setItem('userId', action.user.id);
      }
      return {
        ...state,
        id: action.user.id || state.id,
        sessionId: action.user.sessionId || state.sessionId,
        username: action.user.username || state.username,
        password: action.user.password || state.password
      });
    default:
      return state;
  }
};

Check closer inside the reducer and you will see that we use the reducer’s abstraction to encapsulate inside it the invocation of AsyncStorage setItemmethod.

And to dispatch the SAVE_USER action, we invoke its mapped prop inside Register component like that:

this.props.saveUser();

 

Sources

Similar pages

Page structure
Terms

AsyncStorage

State

React

Key

React Native

Switch

Components

Props

Context