The AsyncStorage
component is a simple key-value store that is globally available to your React Native application. It's persistent, meaning that data within AsyncStorage
will continue to exist through quitting or restarting the application or your phone. If you've worked with HTML LocalStorage
and SessionStorage
, AsyncStorage
will seem familiar. It's powerful for light usage, but Facebook recommends that you use an abstraction layer on top of AsyncStorage
for anything more than that.
As the name implies, AsyncStorage
is asynchronous. If you haven't yet been introduced to asynchronous JavaScript, this means the methods of this storage system can run concurrently with the rest of your code. The methods of AsyncStorage
return a Promise
--an object that represents an operation that hasn't yet completed, but is expected to in the future.
Each of the methods in AsyncStorage
can accept a callback function as an argument, and will fire that callback once the Promise
is fulfilled. This means that we can write our TasksList
component to work around these promises, saving and retrieving our array of tasks when needed.
One final thing about AsyncStorage
though--it's a simple key-value store. It expects a string for both its key and value, which means that we'll need to transform the data we send using JSON.stringify
to turn the array into a string when sending it into storage and JSON.parse
to transform it back into an array when retrieving it.
Play with AsyncStorage
and update your TasksList
component to support it. Here are some goals you'll want to have with AsyncStorage
:
- Once
TasksList
is loaded, we want to see whether any tasks exist locally in storage. If they do, present this list to the user. If they don't, start off with an empty array for storage. Data should always persist through a restart. - When a task is entered, we should update the list of tasks, save the updated list into
AsyncStorage
, and then update theListView
component.
Here's the code I ended up writing:
// TasksList/app/components/TasksList/index.js ... import { AsyncStorage, ... } from 'react-native'; ...
Import the AsyncStorage
API from the React Native SDK.
export default class TasksList extends Component { ... componentDidMount () { this._updateList(); }
Call the _updateList
method during the componentDidMount
life cycle.
... async _addTask () { const listOfTasks = [...this.state.listOfTasks, this.state.text]; await AsyncStorage.setItem('listOfTasks', JSON.stringify(listOfTasks)); this._updateList(); }
Update _addTask
to use the async
and await
keywords as well as AsyncStorage
. Refer to the following for details on using async
and await
:
... async _updateList () { let response = await AsyncStorage.getItem('listOfTasks'); let listOfTasks = await JSON.parse(response) || []; this.setState({ listOfTasks }); this._changeTextInputValue(''); } }
What we are doing with AsyncStorage
in _updateTask
is grabbing the value locally stored using the listOfTasks
key. From here, we parse the result, transforming the string back into an array. Then, we check to see whether the array exists and set it to an empty array if it returns null
. Finally, we set the state of our component by updating listOfTasks
and firing _changeTextInputValue
to reset TextInput
value.
The preceding example also uses the new async
and await
keywords that are part of the ES7 specification proposal and readily available to use with React Native.
Normally, to deal with an asynchronous function, we would chain some promises to it in order to grab our data. We can write _updateList
, like this:
_updateList () { AsyncStorage.getItem('listOfTasks'); .then((response) => {fto return JSON.parse(response); }) .then((parsedResponse) => { this.setState({ listOfTasks: parsedResponse }); }); }
However, this can become quite complicated. Instead, we will use the async
and await
keywords to create a simpler solution:
async _updateList () { let response = await AsyncStorage.getItem('listOfTasks'); let listOfTasks = await JSON.parse(response) || []; this.setState({ listOfTasks }); this._changeTextInputValue(''); }
The async
keyword in front of _updateList
declares it as an asynchronous function. It automatically returns promises for us and can take advantage of the await
keyword to tell the JS interpreter to temporarily exit the asynchronous function and resume running when the asynchronous call is completed. This is great for us because we can express our intent in a sequential order in a single function and still receive the exact same results that we would enjoy with a promise.