第四章:Effect 只负责外部同步
本章先回答“要不要 Effect”,再回答“用了以后如何结束旧同步”,最后把相同的所有权判断应用到 DOM。示例共用 React 19 稳定版和 Vite;把每个独立实验的 App.jsx 替换进已有项目即可运行,不需要第三方依赖。
阅读顺序
- 不需要 Effect 的情况:区分渲染计算、用户事件与外部同步,先删掉多余状态。
- Effect 生命周期、清理与竞态:观察旧请求为何晚到,并用清理保证“只有当前同步能提交结果”。
- Ref 与 DOM 边界:在 DOM 已提交后管理焦点,明确 Ref 可命令什么、不能接管什么。
- 绘制前测量与命令接口:用两遍渲染取得尺寸,再通过 ref prop 暴露有限的操作能力。
- Portal 与可访问关联:区分 DOM 放置、React 事件路径与 label/id 的关系。
从筛选器到请求清理,再到焦点、尺寸和外部容器,可以反复检查同一条边界:值能否由当前快照算出;动作是否由某个事件触发;若都不是,是否有 React 之外的系统需要同步。Ref 提供访问入口,不接管业务 state,也不让任意 DOM 修改都变得合理。
本章可观察成果
- 修改筛选条件时,列表和统计在同一次渲染中一致,不出现“先旧后新”的派生状态。
- 连续发出慢、快请求时,慢响应不能覆盖新结果;切换依赖或卸载会先执行旧清理。
- 打开弹层后输入框得到焦点,关闭后焦点返回触发按钮;组件不直接删除或移动 React 管理的节点。
练习答案集中在本章答案册。请先完成每篇末尾的契约练习,再对照实现和断言。
下一站:类组件维护篇。先比较实例、生命周期与Effect,再进入第五章的等待及错误边界。