Async Storage
We now have have a good way of inputting and store our past moods. However, all our data is stored in-memory. As a result when we refresh the app, all the data will disappear. That's not going to work for a real app. We'll need a way to have all our past moods saved on the device.
#
Async StorageThe most straightforward way of storing data across app launches is using Async Storage. This is the native equivalent of localstorage
from the web and works very similarly. It is a key-value store of data, scoped to the current app. The main difference is unlike localstorage
, accessing AsyncStorage
is an asynchronous operation as the name suggests.
#
Install Async StorageTo install Async Storage, run:
yarn add @react-native-async-storage/async-storage# ornpm install @react-native-async-storage/async-storage
For iOS, install the native dependencies:
cd ios && pod install && cd ..
And rebuild your app from Xcode / Android Studio / cli command.
The api for AsyncStorage is pretty straightforward: you can get, set and delete items from the store based on an ID that can be any string value.
One thing to note is that we can only store things in async storage that are serializable - in short this means that we can't store functions, classes or references.
For starters we'll need to create functions to fetch our app data from storage on launch, and save it when it gets updated.
Open App.provider.tsx
, add functions to set
and get
data from Async Storage:
import AsyncStorage from '@react-native-async-storage/async-storage';
const storageKey = 'my-app-data';
type AppData = { moods: MoodOptionWithTimestamp[],};
const getAppData = async (): Promise<AppData | null> => { try { const data = await AsyncStorage.getItem(storageKey);
if (data) { return JSON.parse(data); } return null; } catch { return null; }};
const setAppData = async (newData: AppData) => { try { await AsyncStorage.setItem(storageKey, JSON.stringify(newData)); } catch {}};
Now we want to fetch the initial data once when the app is first launched. To do this, we can use a useEffect
with an empty dependency array:
React.useEffect(() => { const getDataFromStorage = async () => { const data = await getAppData();
if (data) { setMoodList(data.moods); } }; getDataFromStorage();}, []);
And finally, whenever a mood is updated, we want to also sync this in out Async Storage. For this, let's update our handleAddMood
callback to also save the new value to async storage.
const handleSelectMood = React.useCallback((mood: MoodOptionType) => { setMoodList((current) => { const newValue = [...current, { mood, timestamp: Date.now() }]; setAppData({ moods: newValue }); return newValue; });}, []);
Now when you add new moods to your list and refresh the app, you'll see that the data is persisted across the app launch.