跳到主要内容

Zustand 持久化与中间件

persist 怎样保存并恢复一份状态?​

  • 存储键: 用 name 区分持久化数据,避免多个 store 写入同一键而互相覆盖;
  • 存储适配: createJSONStorage 将满足存储接口的实现包装成 JSON 存储,按需求选择 localStorage、sessionStorage 或异步存储;
  • 数据范围: 只持久化需要跨页面或跨启动保留的数据,函数、DOM 与临时请求状态不适合直接存入;
import { create } from "zustand";
import { persist, createJSONStorage } from "zustand/middleware";

export const usePreferences = create(
persist(
(set) => ({
theme: "light",
setTheme: (theme) => set({ theme }),
}),
{
name: "preferences",
storage: createJSONStorage(() => localStorage),
partialize: (state) => ({ theme: state.theme }),
},
),
);

恢复数据时需要处理哪些时序问题?​

  • 水合完成: 异步存储恢复不是同步初始化,页面在恢复前可能先看到默认值,应按需要显示加载或延迟使用相关状态;
  • 服务端环境: 没有 localStorage,避免在服务器执行浏览器存储逻辑,也要防止客户端初值与服务端 HTML 不一致;
  • 用户隔离: 切换账户时确认哪些持久化数据应清空或按用户隔离,不把本地残留当作当前用户授权状态;

数据结构变化后怎样兼容旧存储?​

  • 版本: 通过 version 标识持久化结构,必要时用 migrate 转换旧数据;
  • 合并: 明确恢复数据与当前默认值如何合并,嵌套对象尤其要避免浅层合并丢字段;
  • 可序列化: 日期、Map 等值需要明确转换策略,JSON 不能保留所有 JavaScript 类型语义;
const persistOptions = {
name: "preferences",
version: 1,
migrate: (stored, version) => {
if (version === 0) {
return { theme: stored.darkMode ? "dark" : "light" };
}
return stored;
},
};
  • 输入校验: 实际迁移还应验证旧数据的结构并提供默认值,本地存储可能缺失、损坏或来自更早版本;

其他中间件分别增强什么能力?​

中间件主要职责
immer简化不可变状态更新
devtools连接开发工具观察状态与动作
subscribeWithSelector为外部订阅选择状态片段
  • 组合原则: 按实际需要选择并验证组合顺序,不把所有中间件默认加入每个 store;