React 的 render 和 commit 有什么区别?
先理解原理和示例,再练习完整口述与追问。
回答要点
render 根据 props / state 计算 UI;commit 应用必要的 DOM 变化。组件重新执行不等于 DOM 必然改变。渲染逻辑应保持纯净,因为渲染可能重复、暂停或被放弃。
原理拆解
render 阶段调用组件并计算下一版 UI,要求保持纯净;React 可以重试或放弃某次计算。commit 阶段把最终确认的变化应用到宿主环境,如更新 DOM 和 ref,并执行相应布局效果;普通 Effect 按调度规则随后运行。组件函数执行次数因此不必等于真实 DOM 修改次数,render 中不能发请求、写外部状态或创建无法回收的订阅。
示例与推演
父组件更新时子函数可能再次执行,但如果最终 DOM 描述没有变化,提交可能没有相应节点修改。开发 StrictMode 也可能额外执行 render 来检查纯度。读取 DOM 并定位浮层属于提交后的工作;给 total 这样的纯派生值赋表达式则可以留在 render,不必再写一个 Effect 同步。
易错点
不要把 render 等同于浏览器 paint,也不要把重渲染一次就称为性能问题。先用 Profiler 确认耗时与实际用户影响。
参考回答可直接练习口述
React 更新通常分 render 和 commit:render 执行组件并计算下一棵 UI,commit 才把必要变化应用到 DOM。重新执行组件不代表所有 DOM 都改变。render 可能被重复执行或被放弃,所以应只根据输入计算输出,不在里面发请求、订阅、改全局变量或操作 DOM。
面试官可能继续问追问与完整解答展开收起
追问
为什么不能在组件函数体里发请求或修改外部变量?父组件重新渲染后子组件是否一定产生 DOM 修改?
追问回答
函数体副作用可能在未提交的渲染里执行,产生重复请求或不一致状态;交互动作放事件处理,与外部系统同步放合适的 Effect。父更新通常会导致普通子组件重新计算,但协调后若 DOM 结果相同,commit 不需要修改相应节点。