Cover Image Credits to Unsplash and Tom Pumford
AsyncStorage
is a simple, asynchronous key-value pair used in React Native applications. It’s used for a variety of scenarios but mainly to store data when your app is not using any cloud services, or when you want to implement features in your app that require data storage.
It operates globally in a React Native app and comes with its own limitations. As a React Native developer, you have to know what these limitations are. One limitation of an AsyncStorage
API is that on Android the size of the database is set to a default of 6MB limit. Also, AsyncStorage
storage is based on SQLite.
Thus, it’s important to keep SQLite limitations in mind, too. Also, it’s hard to store complex and nested data structures in the form of key-value pairs. Knowing about these limitations will help you to opt for the best solution when developing a mobile app.
According to the React Native’s official documentation:
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.
Create an Expo app
To get started, you’ll need to generate a new Expo project. This could be done by opening a terminal window, navigating to a suitable location where you develop projects, and running the following commands in the order they’re described.
expo init offline-app
# navigate inside the app folder
cd offline-app
Note: yarn is currently being used as the package manager. You can also use npm instead of yarn.
Utilizing the AsyncStorage API
In this section, let’s build an app that saves a value to AsyncStorage
and fetches the value from the storage in the client-side React Native app. This will help you learn how to write basic operations using the storage API. Lastly, you’ll learn about how to clear the storage completely.
Open the App.js
file and add the snippet below. Start by importing the necessary components from the React Native API. The most important one here is AsyncStorage
. After that, define a variable named STORAGE_KEY
. This variable will be used to store and retrieve the stored data using the AsyncStorage
API.
Think of it as an identifier for the value being stored or the name of the key in the key-value pair. Since you’re going to store only one value at the moment, there’s only the requirement for one key.
import React from 'react'
import { StyleSheet, Text, View, TextInput, AsyncStorage, TouchableOpacity } from 'react-native'
const STORAGE_KEY = '@save_name'
Next, let’s define an initial state with two empty strings. They’re going to be used to save the value of the user input and then retrieve the value to display it on the app screen. After defining the initial state, there’s going to be a lifecycle method that will load the data when the application starts for the first time, or when the App component renders.
class App extends React.Component {
state = {
text: '',
name: ''
}
componentDidMount() {
this.retrieveData()
}
// ...
}
In the above snippet, note that the App
component is actually a class component and not the default functional component that comes with boilerplate Expo app.
Read the data
There are three asynchronous methods that will help to store the data, retrieve the data, and clear the app data that are stored. Each of these methods is going to utilize the appropriate API method from the AsyncStorage
API. Every method in the AsyncStorage API is promise-based; hence, let’s use async/await
syntax to follow best practices.
retrieveData = async () => {
try {
const name = await AsyncStorage.getItem(STORAGE_KEY)
if (name !== null) {
this.setState({ name })
}
} catch (e) {
alert('Failed to load name.')
}
}
In the above snippet, the name of the method implies what it’s going to do in the app. The retrieveData
method is what fetches the data from storage if it exists. It uses the same identifier that you defined previously, outside the class function component. It utilizes the parameter in the state object name.
Note that there’s an if condition inside this method. This condition makes sure that data is fetched only when a value for the name variable exists. This method also uses try/catch
, as they are part and parcel of writing functions with modern async/await
syntax. Lastly, this method is being invoked inside the lifecycle method.
Save the Data
The next function is going to save the data. In the below snippet, you’ll find that it uses a parameter name, which, on success, is the value that’s stored. An alert message will be shown when the input data is saved.
save = async name => {
try {
await AsyncStorage.setItem(STORAGE_KEY, name)
alert('Data successfully saved!')
this.setState({ name })
} catch (e) {
alert('Failed to save name.')
}
}
Remove Everything
The last method that you are going to utilize from the AsyncStorage
API is called clear()
. This deletes everything that is previously saved. It is not recommended to use this method directly if you want to delete only a specific item from the storage. For that, there are methods like removeItem
or multiRemove
available by the API. You can read more about them in the official documentation here or later when building the Todolist application.
removeEverything = async () => {
try {
await AsyncStorage.clear()
alert('Storage successfully cleared!')
} catch (e) {
alert('Failed to clear the async storage.')
}
}
This snippet will throw an alert box on the device screen when everything is cleared from storage.
Completing the App
The last two methods are going to be used to create a controlled input.
onChangeText = text => this.setState({ text })
onSubmitEditing = () => {
const onSave = this.save
const { text } = this.state
if (!text) return
onSave(text)
this.setState({ text: '' })
}
After that, add the code snippet for the render
method, followed by the styles for each UI component. Lastly, don’t forget to export the App
component so it can run on the simulator or the real device.
render() {
const { text, name } = this.state
return (
<View style={styles.container}>
<TextInput
style={styles.input}
value={text}
placeholder='Type your name, hit enter, and refresh'
onChangeText={this.onChangeText}
onSubmitEditing={this.onSubmitEditing}
/>
<Text style={styles.text}>Hello {name}!</Text>
<TouchableOpacity onPress={this.removeEverything} style={styles.button}>
<Text style={styles.buttonText}>Clear Storage</Text>
</TouchableOpacity>
</View>
)
}
} // class component App ends here
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center'
},
text: {
fontSize: 20,
padding: 10,
backgroundColor: '#00ADCF'
},
input: {
padding: 15,
height: 50,
borderBottomWidth: 1,
borderBottomColor: '#333',
margin: 10
},
button: {
margin: 10,
padding: 10,
backgroundColor: '#FF851B'
},
buttonText: {
fontSize: 14,
color: '#fff'
}
})
export default App
Running the App
Now to run the application, go to the terminal window and execute the command expo start
. After that, you’ll see the following screen on the simulator.
Since there’s no data stored right now, the text after the word Hello
is empty. Use the input field to save a string or a name or anything you’d like, and then press the enter key. You’ll get the following output. Whatever input you entered, it will be displayed next to the word Hello
.
Even if you refresh the Expo client, the value stored doesn’t go away. Only when pressing the button below the Hello
statement that says Clear Storage
will the stored value be removed.
Refresh the Expo client after you clear the storage to get the following output.
Conclusion
This completes the section about using AsyncStorage
API to save and fetch the data.
If you'd like to learn more about using AsynStorage API
in a real-time React Native app, learn how to build a complete Todolist app here. In this post, you are going to use Native Base UI component library.
Here is short TLDR of the Todolist post:
- Adding navigation
- Creating a Floating Action Button (FAB)
- Navigating between two screens
- Customize the header component
- Rendering a list of items using FlatList
- Reading data using the AsyncStorage API
- Adding a to-do list item
- Deleting a to-do list item
- Mark an item check or uncheck upon completion
- Passing data between different screens using the navigation
- Display each to-do list item
- Bonus section: Adding a segment
Here is a little demo of what you are going to build in the Todolist post:
I often write on Nodejs, Reactjs, and React Native. You can visit me on amanhimself.dev or you can subscribe to my weekly newsletter to receive all updates on new posts and content, straight in your inbox 💌.
Top comments (7)
The 6mb limit is not accurate. It’s unlimited on iOS and configurable on android. Just thought you’d wanna know.
Thanks! What I wanted to say was that on Android it is the default size. I'll make amendments.
To increase the limit
Ref: github.com/stockulus/pouchdb-react...
Is there an upper limit to this? What if I need to store big video files?
If iOS has unlimited storage, i think it would be safe to say the same on android, i'm no expert and had no extensive experience in Android but i think to have the most reliable answer is to look at the Documentation.
Check the official docs for Android here: github.com/react-native-community/...
hey @flexgrip472
you are 100 % sure ?
do you have any docs where i can confirm this ?