Skip to content
目录

状态更新和合并机制

Zustand 的更新路径:set / setState → 合并或替换 → Object.is 短路 → 通知所有 listener。掌握 partial vs replace浅合并边界 可避免「嵌套字段丢了」类 bug。


1. setState API 形态

调用含义
set({ k: v })默认 partial,顶层浅合并
set(fn)fn(prev) 返回 partial 或新 state
set(obj, true)replace,整棵 state 替换为 obj

React 里 set 即 store 的 setState;中间件可能包装 set(如 Immer 传入 draft)。


2. 浅合并(默认)

当前 state 与 partial 顶层 Object.assign

  • 只改 count 时,useritems 等同层引用保留。
  • set({ user: { name: 'A' } })整个替换 user 键,不会与旧 user.age 深合并。

嵌套更新选项

  1. 手动展开:set(s => ({ user: { ...s.user, name: 'A' } }))
  2. immer 中间件:set(s => { s.user.name = 'A' })
  3. 扁平化 state 结构,减少深层嵌套

3. 完全替换(replace: true)

用于:

  • state 形态切换(登出清空)
  • partial 非对象(primitive store)
  • 明确不要保留旧 key 时

replace 为 true 时不会做 assign,旧 key 若未出现在新对象中会消失


4. 函数式更新

set(state => ({ count: state.count + 1 })) 基于当前 store 最新值,适合连续多次更新、避免闭包旧值。

与 React setState 函数式更新类似,但发生在 store 层,一次 set 仍触发一轮 listener 通知(React 18 下多次 set 可能被批处理渲染)。


5. 何时不触发订阅

合并/替换后 Object.is(newState, oldState)不通知。用于:

  • 误写 set({}) 且无变化
  • Immer 返回相同引用(未 mutate)

6. 与 React 渲染的关系

  1. setState 同步调用所有 listener。
  2. 已挂载组件通过 useSyncExternalStore 在下次渲染读新快照。
  3. 选择器返回新引用 → 该组件重渲染(见 07-性能优化)。

7. 常见错误对照

现象常见原因
嵌套字段被「抹掉」浅合并 + 只传了子对象一半字段
更新了 UI 不变选择器引用未变;或 Object.is 判定相等
异步里读到旧 state应用 get() 或函数式 set

8. 总结

  • 默认浅合并,只管顶层 key。
  • replace: true 整表替换。
  • 函数式 set 对齐最新 store。
  • 深层结构优先 Immer 或扁平 state。

实现细节见 02-VanillaStore

MIT License.