fbpx Skip to content

Aquent | DEV6

Simple Cross-Platform Persistence in React Native

Written by: James McGeachie

At some point, most applications require data persistence. You can do this by saving to a database on a remote server.  However, sometimes you need to store data on the mobile client itself.

So, if we’re building a React Native mobile application, how do we approach persistence? Is there a simple abstraction available to us in JavaScript that can make this job easy? The answer is “Yes” – the AsyncStorage API.

Why Client-side Persistence?

Before we talk about AsyncStorage, I want to elaborate briefly on why it matters. Some of you may be used to storing everything on the server and have not come across a need for client-side persistence.  However, there are a few categories of app that rely heavily on it.

  • Apps with partial-offline support – aka “occasionally connected”.
  • Apps that are fully offline (no server)

In the case of partial-offline support, you may wish to synchronize user data with the server when network connectivity returns, and you do not want to lose that data when the app is terminated.  In the case where the app has no server, all data is going to live on the device forever and, thus, it totally depends on a client-side solution.

I want to stress that some level of offline support is something users want and expect in modern applications. So, client-side persistence is absolutely something that should be considered for your application and, therefore, the earlier you consider how you’re going to handle it, the better.

Async Storage

So, what actually is AsyncStorage? The following is the official description from the RN docs:

“AsyncStorage is a simple, unencrypted, asynchronous, persistent, key-value storage system that is global to the app.”

Note: this is a simple key-value store.  We are not talking about a fully-featured relational database.  If you’re looking for that, perhaps this isn’t the right solution.  However, in most mobile application use cases, you’ll be storing a limited set of data for only one user and, thus, it fits these cases quite nicely.  The fact that it’s asynchronous is ideal because it doesn’t block other execution and allows the user to continue using the app.

Also worth noting from the docs is how the actual persistence is implemented:

On iOS, AsyncStorage is backed by native code that stores small values in a serialized dictionary and larger values in separate files. On Android, AsyncStorage will use either RocksDB or SQLite based on what is available.”

Cross-platform app development is easiest when we don’t have to get bogged down in platform-specific implementations and optimizations, so personally I love having this abstracted away.  Of course, there will be the odd time it comes back to bite you with a lower level error message that throws you off guard, but, personally, I feel the development experience and speed to get going makes it worth it over all.

Getting Started

To introduce the API, let’s look at how to do the 2 simplest operations: reading and writing a single value.

As AsyncStorage is packaged with the framework, we start by importing it from React Native.

import { AsyncStorage } from ‘react-native’;

We now have immediate access to all the static methods on the AsyncStorage class.

Writing Data

Let’s say we want to save the current user’s details, and we’ve structured those details in an object. For this task, we’ll need the setItem method.  This method takes 3 parameters:

  • key: string
  • value: string
  • callback: function(error) (optional)

So, using it to store the current user could look like this:

AsnycStorage.setItem(‘currentUser, JSON.stringify(currentUser), handleError);

Note that because all values stored in AsyncStorage are strings, we need to convert our object into a JSON string.

Now, from the name, it’s implied that this is saving our data asynchronously.  If that’s the case, when do we know the action is complete?  Well, this method returns a JavaScript Promise, which resolves when persistence is complete.  So, we can chain off of the method call as follows:

AsnycStorage.setItem(‘currentUser’, JSON.stringify(currentUser))
 
    .then(() => console.log(‘User successfully saved.’})
 
    .catch(handleError)

If you plan to chain off of the Promise, then you may also use a catch block to handle the error rather than the third parameter, as that’s a common practice in the JS community.  (You may also forgo the ‘then’ syntax and use ES2017’s Async Await, but that’s a topic for another day).

Reading Data

Now that we’ve saved our current user, how do we later retrieve it?  For this, we use the getItem method which takes 2 parameters:

  • key: string
  • callback: function(error) (optional)

In the case of loading, we’ll need to chain off of the Promise in order to handle our loaded value.  So, we could write something like this:

AsnycStorage.gettItem(‘currentUser’)
 
    .then((currentUser: string) => {
 
        this.currentUser = JSON.parse(user);
 
    })
 
    .catch(handleError)

Note that we parse the stored JSON string back into a JS Object once we read the value.

Next Steps

And that’s that!  We now know a super simple way to begin saving and loading data within a React Native application.  From here, however, you may have some more questions, like: “How do I remove an item?” or “Can I save multiple, separate items at once”.  For both of those, the answer is “Yes” and you’ll want to check out the RN docs to learn more on the methods to do so.

Also, check back in the future to read more blogs on React Native development.

Interested in learning more React Native?

Check out our React Native training course

View Course Details