Skip to content
雲里
里雾

Zustand 与状态管理演变

mindgym 开发 更新于 2026/4/12

Zustand 是一个极简的 React 状态管理库,核心代码约 40 行,基于发布-订阅模式。它和 Redux 解决同一个问题(跨组件共享状态 + 精准重渲染),但去掉了 Redux 的 action/reducer/dispatch 间接层。本页从状态管理的演变出发,梳理 Zustand 的设计动机和内部原理。


概述

为什么需要状态管理

useState 管理组件内部状态足够,但跨组件共享状态时产生 prop drilling 问题——状态要一层层通过不关心它的组件传递。useContext 解决了 prop drilling,但缺乏精准重渲染(Context value 任何字段变化都触发所有消费组件重渲染)和中间件能力(持久化、日志、devtools)。

状态管理库的核心价值:跨组件共享 + selector 精准重渲染 + middleware 生态。

状态管理演变线

时期方案解决的问题引入的新问题
2014Flux数据流混乱(双向绑定)架构模式无统一实现,生态碎片化
2015Redux统一了 Flux 实现,single source of truthboilerplate 多(action type + creator + reducer)
2017Redux Toolkit减少 boilerplate心智模型仍是 action → dispatch → reducer
2015/2019MobX自动追踪依赖”魔法”行为不透明,调试不如 action log
2019Zustand极简 API,无 Provider无 action log,调试可追溯性弱
2020Jotai原子化状态大量 atom 难以管理全局视图
2021ValtioProxy 直接修改Proxy 行为有时不直观

工作方式

Vanilla Store(与 React 无关)

Zustand 的核心是一个不依赖 React 的可订阅对象:

function createStore(createState) {
  let state
  const listeners = new Set()
  const setState = (partial) => {
    state = Object.assign({}, state, partial)  // 浅合并
    listeners.forEach((l) => l(state))         // 通知订阅者
  }
  const getState = () => state
  const subscribe = (l) => { listeners.add(l); return () => listeners.delete(l) }
  state = createState(setState, getState)
  return { getState, setState, subscribe }
}

这和 Redux createStore 底层一样是发布-订阅。区别:Redux 更新走 dispatch(action) → reducer,Zustand 直接调 setState(partial)

不需要 Provider 的原因

Redux 的 React 绑定通过 Context 注入 store 实例,所以需要 <Provider>。Zustand 的 store 是模块作用域的闭包变量(单例),import Hook 就能访问,不需要 Context 传递。

trade-off:不能在同一个应用里用不同 Provider 注入不同 store 实例(微前端场景可能需要)。

React 绑定:useSyncExternalStore

Zustand 的 Hook 内部使用 React 18 的 useSyncExternalStore 连接外部 store 和 React 渲染系统。这个 API 保证在 concurrent mode 下不会发生 tearing(同一次渲染中不同组件读到不同版本的状态)。

Selector 精准重渲染

const locale = useSettingsStore((state) => state.locale)

每次 store 更新,Zustand 调用 selector 取新值,和上次用 Object.is 比较。只有返回值变化才触发重渲染。

陷阱:selector 返回新对象时((s) => ({ a: s.a, b: s.b })),每次都是新引用,导致不必要重渲染。用 useShallow 做逐字段浅比较解决。

set() 的浅合并

set({ locale: 'en' }) 只覆盖 locale,其他字段保留。Redux reducer 必须 return { ...state, locale } 手动展开。但浅合并只作用于第一层——嵌套对象需要手动处理或用 immer middleware。

Middleware 函数组合

create()(
  devtools(persist(immer((set) => ({...}))))
)

middleware 是高阶函数的嵌套组合(compose 模式),不是 Redux 的 dispatch 管道拦截器。每层 middleware 增强 set/get 的行为。


与 Redux Toolkit 对比

维度Redux ToolkitZustand
更新方式dispatch(action)set(partial) 直接调函数
Provider必须不需要
boilerplateslice + store config + Provider1 个 create() 调用
Action 可序列化是,完整 action log
时间旅行调试一等公民devtools middleware 部分支持
异步模式createAsyncThunk, RTK Query自行在 action 里写 try-catch
持久化需要 redux-persist + 配置内置 persist middleware

Redux 更好的场景:大团队需要 action 审计、复杂异步工作流、time-travel debugging、RTK Query 做 server state 管理。

Zustand 更好的场景:中小型应用、状态简单、不需要 action log、追求最少 boilerplate。


Zustand 的诚实缺点

  1. 无 action log:调用 set() 不产生可序列化的 action,状态变更的”历史记录”不如 Redux 完整
  2. 测试不如 Redux 方便:没有 Provider 意味着不能用不同 Provider 注入 mock store,需要用 store.setState() 手动重置
  3. 大型团队缺乏约束:Redux 的 action/reducer 分离强制了一种代码组织规范,Zustand 的”自由”在大团队里可能导致 store 结构混乱
  4. 社区和生态不如 Redux 成熟:虽然 npm 下载量已超 Redux,但 Redux 的中间件生态(saga, observable, persist, logger)和教程资源仍然更丰富

版本说明

本页基于 MindGym M1 阶段(Expo SDK 54, Zustand 5.x, 2026-04-13)。

参见

参考