Data persistance
To ensure our shopping list does not disappear every time we kill the app, we'll need to store it in the device's storage.
For this, we'll be using AsyncStorage - an unencrypted key-value store for React Native. It's very similar to localStorage
on the web, only as the name suggests, the calls to is are asynchronous.
Install Async Storage
npx expo install @react-native-async-storage/async-storage
util function
There's two parts to this: we want to get from storage and save to storage. Since we're doing JSON parsing, it's usually a good idea to put these values in a try / catch.
New file: utils/storage.ts
import AsyncStorage from "@react-native-async-storage/async-storage";
export async function getFromStorage(key: string) {
try {
const data = await AsyncStorage.getItem(key);
return data ? JSON.parse(data) : null;
} catch {
return null;
}
}
export async function saveToStorage(key: string, data: object) {
try {
await AsyncStorage.setItem(key, JSON.stringify(data));
} catch {}
}
Fetch initial data
Use the useEffect
hook fetch the initial data - once - when the app launches.
Update: app/index.tsx
@@ -1,7 +1,10 @@
import { StyleSheet, TextInput, FlatList, View, Text } from "react-native";
import { theme } from "../theme";
import { ShoppingListItem } from "../components/ShoppingListItem";
-import { useState } from "react";
+import { useEffect, useState } from "react";
+import { getFromStorage } from "../utils/storage";
+
+const storageKey = "shopping-list";
type ShoppingListItemType = {
id: string;
@@ -14,6 +17,17 @@ export default function App() {
const [shoppingList, setShoppingList] = useState<ShoppingListItemType[]>([]);
const [value, setValue] = useState<string>();
+ useEffect(() => {
+ const fetchInitial = async () => {
+ const data = await getFromStorage(storageKey);
+ if (data) {
+ setShoppingList(data);
+ }
+ };
+
+ fetchInitial();
+ }, []);
+
const handleSubmit = () => {
if (value) {
const newShoppingList = [
Sync updates
And update the shopping list in storage whenever an item is modified (deleted or update)
Update: app/index.tsx
@@ -2,7 +2,7 @@ import { StyleSheet, TextInput, FlatList, View, Text } from "react-native";
import { theme } from "../theme";
import { ShoppingListItem } from "../components/ShoppingListItem";
import { useEffect, useState } from "react";
-import { getFromStorage } from "../utils/storage";
+import { getFromStorage, saveToStorage } from "../utils/storage";
const storageKey = "shopping-list";
@@ -39,6 +39,7 @@ export default function App() {
...shoppingList,
];
setShoppingList(newShoppingList);
+ saveToStorage(storageKey, newShoppingList);
setValue(undefined);
}
};
@@ -62,6 +63,7 @@ export default function App() {
return item;
}
});
+ saveToStorage(storageKey, newShoppingList);
setShoppingList(newShoppingList);
};
As your application grows, you'd usually end up reaching for a state management library instead of managing this data storage step yourself. Most JavaScript state management libraries work in React Native, and they almost always include an adapter of sorts that allows you to use Async Storage to persist the data offline.