Хранение данных: AsyncStorage
Сейчас задачи живут только в состоянии и исчезают, когда приложение закрывают. AsyncStorage — простое хранилище «ключ — строка» на устройстве, аналог localStorage из браузера. Отличие в том, что все его методы асинхронные и возвращают промисы.
Установка
Вернитесь в проект списка задач todo и установите пакет:
npx expo install @react-native-async-storage/async-storageПакет входит в Expo Go, поэтому собирать приложение заново не нужно — достаточно перезапустить npx expo start.
Запись и чтение
| Метод | Что делает |
|---|---|
AsyncStorage.setItem(key, value) | Сохраняет строку |
AsyncStorage.getItem(key) | Возвращает строку или null |
AsyncStorage.removeItem(key) | Удаляет значение |
Хранятся только строки, поэтому массив задач превращают в JSON. Удобно вынести это в отдельный файл:
// lib/storage.ts
import AsyncStorage from '@react-native-async-storage/async-storage';
import type { Task } from '@/components/TaskItem';
const KEY = 'tasks';
export async function loadTasks(): Promise<Task[]> {
const json = await AsyncStorage.getItem(KEY);
return json ? JSON.parse(json) : [];
}
export async function saveTasks(tasks: Task[]) {
await AsyncStorage.setItem(KEY, JSON.stringify(tasks));
}Создайте папку lib в корне проекта. loadTasks возвращает пустой массив, если сохранений ещё нет.
Подключение к экрану
На главном экране загрузите задачи один раз при открытии и сохраняйте их при каждом изменении:
// app/index.tsx
import { loadTasks, saveTasks } from '@/lib/storage';
const [tasks, setTasks] = useState<Task[]>([]);
const [loaded, setLoaded] = useState(false);
useEffect(() => {
loadTasks().then((saved) => {
setTasks(saved);
setLoaded(true);
});
}, []);
useEffect(() => {
if (loaded) saveTasks(tasks);
}, [tasks, loaded]);Добавьте пару задач, закройте приложение полностью и откройте снова — задачи на месте. Флаг loaded разрешает сохранение только после загрузки.
Где лежат данные
AsyncStorage хранит данные в обычном файле приложения без шифрования. Удаление приложения стирает их. Подходит для настроек, черновиков, кеша и списков вроде нашего. Для больших объёмов и сложных запросов используют базу данных expo-sqlite.
Частая ошибка
Сохранять без флага загрузки:
// app/index.tsx
// Неправильно:
useEffect(() => {
saveTasks(tasks);
}, [tasks]);При первом рендере tasks — пустой массив, и эффект записывает его в хранилище раньше, чем loadTasks успеет прочитать старые задачи. После каждого перезапуска список будет пустым. Сохраняйте только после того, как данные загружены.