使用 AsyncStorage 持久化 Zustand 状态
使用由 AsyncStorage 支持的持久化中间件包裹 Zustand 存储,使状态在应用重启后仍然保留,并处理重新水合的时机。
使用 AsyncStorage 持久化 Zustand 状态 是 CoddyKit 上的免费 React Native Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 React Native Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 React Native Academy 课程共包含 4 节课。
本课时的部分内容尚未翻译,以英文显示。
Why Persist State?
By default, Zustand state lives only in memory and is lost when the app closes. Persisting state means saving it to the device's local storage so it survives app restarts. This is essential for user preferences, authentication tokens, shopping carts, or any data the user expects to still be there when they reopen the app.
Installing AsyncStorage
AsyncStorage is the standard key-value storage API for React Native. In Expo managed workflow, install the community package @react-native-async-storage/async-storage. Zustand's built-in persist middleware works with any storage adapter, and AsyncStorage is the most common choice for mobile apps.
npx expo install @react-native-async-storage/async-storageAdding the persist Middleware
Wrap the store creator with persist imported from zustand/middleware. Pass it your store factory and a configuration object with a name key (the AsyncStorage key where state will be saved) and a storage key (pointing to your AsyncStorage adapter). Zustand handles reading and writing automatically.
import { create } from 'zustand';
import { persist, createJSONStorage } from 'zustand/middleware';
import AsyncStorage from '@react-native-async-storage/async-storage';
export const useSettingsStore = create(
persist<SettingsStore>(
(set) => ({
theme: 'light',
notifications: true,
setTheme: (theme) => set({ theme }),
toggleNotifications: () =>
set((state) => ({ notifications: !state.notifications })),
}),
{
name: 'settings-store',
storage: createJSONStorage(() => AsyncStorage),
}
)
);How Persist Works Internally
When the store is first created, persist reads from AsyncStorage and rehydrates (restores) any previously saved state before rendering the first component. When state changes via set, persist automatically serializes the state to JSON and writes it to AsyncStorage asynchronously. This all happens without any extra code in your components.
Handling the Rehydration Delay
AsyncStorage reads are asynchronous, so on the first render the store may still contain the initial state before rehydration finishes. Zustand's persist middleware adds a _hasHydrated flag and an onFinishHydration callback. Use these to show a loading screen while persisted state is loading from disk.
const hasHydrated = useSettingsStore((state) => state._hasHydrated);
if (!hasHydrated) {
return <ActivityIndicator />; // Show loading until store is ready
}
// Alternatively, listen to hydration completion:
useEffect(() => {
const unsub = useSettingsStore.persist.onFinishHydration(() => {
setReady(true);
});
return unsub;
}, []);Persisting Only Part of the State
You often do not want to persist everything in the store — for example, transient loading states or error messages should not be saved. Use the partialize option to select which fields to persist. The returned object contains only the keys you want to write to AsyncStorage.
persist<AuthStore>(
(set) => ({
user: null,
token: null,
isLoading: false, // transient — don't persist
error: null, // transient — don't persist
login: (user, token) => set({ user, token }),
logout: () => set({ user: null, token: null }),
}),
{
name: 'auth-store',
storage: createJSONStorage(() => AsyncStorage),
partialize: (state) => ({ user: state.user, token: state.token }),
}
)Versioning and Migration
When you change the structure of your persisted state in a new app release, old data on users' devices may not match the new shape. Use the version and migrate options to upgrade stored state from one version to the next. Increment version with each structural change and handle old state in the migrate function.
persist<SettingsStore>(
(set) => ({ /* ... */ }),
{
name: 'settings-store',
storage: createJSONStorage(() => AsyncStorage),
version: 2,
migrate: (persistedState: any, version: number) => {
if (version === 1) {
// Rename darkMode to theme in version 2
persistedState.theme = persistedState.darkMode ? 'dark' : 'light';
delete persistedState.darkMode;
}
return persistedState;
},
}
)Clearing Persisted State
To clear the persisted state — for example when the user logs out — call useStore.persist.clearStorage(). This removes the data from AsyncStorage. You can also call useStore.getState().reset() to clear the in-memory state at the same time. Doing both ensures the user starts fresh on the next app launch.
async function handleLogout() {
// Clear in-memory state
useAuthStore.getState().logout();
// Clear persisted state from AsyncStorage
await useAuthStore.persist.clearStorage();
navigation.reset({ index: 0, routes: [{ name: 'Login' }] });
}Using SecureStore for Sensitive Data
For sensitive values like auth tokens, prefer Expo SecureStore over plain AsyncStorage. SecureStore uses the device's secure enclave (iOS Keychain / Android Keystore) to encrypt data at rest. You can create a custom Zustand storage adapter using SecureStore's getItemAsync and setItemAsync methods.
import * as SecureStore from 'expo-secure-store';
const secureStorage = {
getItem: async (name: string) => await SecureStore.getItemAsync(name),
setItem: async (name: string, value: string) =>
await SecureStore.setItemAsync(name, value),
removeItem: async (name: string) =>
await SecureStore.deleteItemAsync(name),
};
// Use secureStorage instead of AsyncStorage:
storage: createJSONStorage(() => secureStorage),Debugging Persisted State
To inspect what is stored in AsyncStorage during development, call AsyncStorage.getAllKeys() and AsyncStorage.multiGet(keys) in the dev console or a debug screen. You can also manually clear stale persisted state with AsyncStorage.clear() when testing migration logic. Always test with a fresh install to simulate real user upgrade scenarios.
// Debug helper — call from a dev-only screen
async function printStorage() {
const keys = await AsyncStorage.getAllKeys();
const pairs = await AsyncStorage.multiGet(keys);
pairs.forEach(([key, value]) => {
console.log(key, ':', JSON.parse(value ?? 'null'));
});
}Persisting a Cart Store Example
Here is a realistic cart store that persists its items list across app restarts. Loading and error state are excluded from persistence using partialize. The total is derived on the fly in the component rather than stored, so it is always consistent with the items array after rehydration.
export const useCartStore = create(
persist<CartStore>(
(set, get) => ({
items: [],
addItem: (item) => set((state) => ({ items: [...state.items, item] })),
removeItem: (id) =>
set((state) => ({ items: state.items.filter((i) => i.id !== id) })),
clearCart: () => set({ items: [] }),
}),
{
name: 'cart-store',
storage: createJSONStorage(() => AsyncStorage),
partialize: (state) => ({ items: state.items }),
}
)
);Quick Check
Test your understanding of React Native Mobile Development concepts from this lesson.
Lesson Recap
In this lesson you learned: the persist middleware wraps a Zustand store to save and restore state from AsyncStorage automatically, partialize controls which fields are persisted to avoid saving transient loading or error state, and version with migrate handles breaking state shape changes across app updates. Next up we explore the slices pattern and Devtools integration in Zustand.
常见问题解答
「使用 AsyncStorage 持久化 Zustand 状态」课时是免费的吗?
是的 — 「使用 AsyncStorage 持久化 Zustand 状态」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 React Native Academy 课程的其余内容,请升级到 CoddyKit PRO。 React Native Academy 课程共包含 4 节课。
「使用 AsyncStorage 持久化 Zustand 状态」这节课中我会学到什么?
使用由 AsyncStorage 支持的持久化中间件包裹 Zustand 存储,使状态在应用重启后仍然保留,并处理重新水合的时机。 你通过在浏览器中直接运行的动手代码来练习 React Native Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 React Native Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 React Native Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。
「使用 AsyncStorage 持久化 Zustand 状态」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 React Native Academy 课中编写并运行代码吗?
能。每节 React Native Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 创建 Zustand 存储
- 在组件中读取和更新存储状态
- 使用 AsyncStorage 持久化 Zustand 状态
- 切片模式与 Devtools 集成