跳到主要内容

渲染与提交

一次界面更新怎样从请求到显示?​

  • 触发: 首次调用 root.render,或组件及祖先的状态更新,向 React 请求工作;
  • 渲染: React 调用组件,递归计算这一次 UI 应该是什么;
  • 提交: React 把需要的变更应用到 DOM,随后浏览器按自己的流程绘制像素;
状态更新 / 首次渲染
↓
调用组件,计算 UI
↓
提交需要的 DOM 变更
↓
浏览器绘制

重新渲染是否意味着重新创建全部 DOM?​

  • 组件调用: 父组件渲染时通常继续渲染它返回的子组件,性能优化可以减少不必要的工作;
  • DOM 复用: 重新执行函数不等于替换所有节点,React 会尽量保留可复用 DOM,只提交必要差异;
  • 可见结果: 如果输出相同,一次重新渲染可能不产生任何 DOM 修改,因此不要仅凭日志次数推断页面重建;
function Clock({ time }) {
return (
<section>
<h1>{time}</h1>
<input aria-label="草稿" />
</section>
);
}
  • 观察方式: 先在输入框输入草稿,再改变 time;只要树中身份保持一致,标题更新不应清空输入框,说明函数重新执行与 DOM 重建不是同一件事;

为什么渲染阶段不能直接操作外部世界?​

  • 可重试计算: 一次渲染可能被重做或放弃,计算结果未必提交;在这里发请求或改 DOM 会留下与最终 UI 不匹配的副作用;
  • 纯度规则: 相同输入与局部修改的具体要求见保持组件纯粹;

如何理解提交与浏览器绘制的区别?​

  • DOM 提交: 更新页面节点与属性,使 DOM 对应新的 React 输出;
  • 浏览器绘制: 浏览器根据 DOM、样式和布局把像素显示出来,它是与 React 计算不同的阶段;
  • Effect 时机: 不能把所有 Effect 简化为“绘制后执行”,需要按 useEffect 与 useLayoutEffect 的契约选择,见 Effect Hooks;

何时才需要优化渲染?​

  • 先测量: 发现可感知延迟后用 Profiler 定位昂贵子树,确认成本来自计算、DOM、网络还是其他环节;
  • 优化方向: 保持状态局部、减少无谓 Effect,再评估缓存或非阻塞更新;不要为了减少日志而改变正确语义;