第三章:让状态变化拥有清楚的边界
本章先把转换集中为纯 reducer,再解决树中深层读取与 React 外部 Store,最后沿不可变引用继续研究计算缓存。状态转换、数据传递、外部订阅与渲染优化各自解决一个问题,需要先判断问题属于哪一层。
具体前置
- 能把“新增、修改、删除”分别写成返回新对象/数组的纯函数;
- 理解 setter/dispatch 都为下一次渲染排队,当前快照不会改变;
- 能判断 state 应提升到哪个共同祖先,知道 key 改变会重置子树;
- 所有示例运行于 React 19 + Vite,不安装 Redux、Zustand 或其他包。
依赖顺序
- 从状态到 reducer:用 action 记录发生了什么,用 reducer 决定状态怎样转换。
- Context 的边界:把稳定依赖送到深层消费者,同时保持 Provider 作用域和缺失错误可见。
- 自定义 Hook 与外部 Store:封装订阅协议,理解“复用逻辑”不等于“自动共享 state”。
- 引用身份与缓存:用对照实验解释 memo、useMemo 和 useCallback,检查依赖与旧闭包。
可观察成果
- reducer 对同一 state/action 得到相同逻辑结果;已知但不允许的转换返回原对象,未知 action 抛错;
- 两个嵌套主题 Provider 各自影响自己的子树,Provider 外的自定义 Hook 不会静默吃默认值;
- 两个组件通过
useSyncExternalStore读取同一外部计数,任一处更新都同步刷新;重复读取未变化 Store 得到同一快照,退订函数能移除监听器。 - 无关的页面配色变化可以复用筛选结果与函数 prop;筛选条件变化仍正确更新结果,函数不会因缺失依赖读到旧值。
完成后再看第三章练习答案。