
官方能给的:三步
Render and Commit 把一次界面更新拆成三步:
- 触发。初次渲染调
root.render(),之后由 state 更新排入一次渲染。 - 渲染。React 调用你的组件,拿到描述界面的对象树。初次渲染从根组件开始;重渲染从「state 变了的那一个组件」开始,再递归到它返回的子组件。
- 提交。React 改 DOM。
两个阶段的分工是理解这套流程的关键:渲染阶段只算出要改什么,提交阶段才真的动 DOM。官方的原话是,重渲染时「应用必要的最小改动,而这些改动是渲染期间算出来的」。
一个能看出差别的例子
function Clock({ time }) { return ( <> <h1>{time}</h1> <input /> </> )}父组件每秒给它一个新的 time。你在输入框里打字,字不会因为重渲染消失:
import { useState, useEffect } from 'react'import Clock from './Clock.js'
function useTime() { const [time, setTime] = useState(() => new Date()) useEffect(() => { const id = setInterval(() => setTime(new Date()), 1000) return () => clearInterval(id) }, []) return time}
export default function App() { const time = useTime() return <Clock time={time.toLocaleTimeString()} />}原因在提交阶段:React 只把 <h1> 的内容换成新时间。它看到 <input> 还在原来的位置,就没碰它,也没碰它的值。
官方把这条总结成一句:两次渲染结果相同,React 就不碰 DOM。
再往里,就是社区的重构了
这里必须把来源说清楚,否则很容易把社区的解释当成官方规范。
react.dev 没有 Fiber 的文档,也没有调度器或 diff 算法的文档。 你在这几个词上能查到的权威来源只有一份:Andrew Clark 的 react-fiber-architecture。他在 README 开头写的是「我不在 React 团队,不代表任何权威,这不是官方文档」,并自述这份文档「远未完成」;仓库在 2024 年 7 月之后也没有再更新。
社区普遍引用的那套重构是:
- 把元素树转换成一棵由 Fiber 节点组成的树,每个节点是最小工作单元,用
child、sibling、return三个指针串起来,这样遍历可以随时中断、之后再恢复。 - 有一个调度器按优先级把工作切成小段推进,遍历时对每个节点调用处理函数。
- 渲染阶段可中断,提交阶段不可中断。
- 提交完成后切换双缓冲指针,把工作树变成当前树。
把它当成「社区对内部实现的解释」来读,它很有用。它解释得了一个现象:为什么渲染能被用户输入打断。但字段名、函数名、时间片长度这些细节会随版本变,写进文章时要注明年代与来源。
官方能查到的只有行为级描述。例如 useTransition 那一页说的是「过渡更新可被打断」,不讲内部怎么实现。
那张「5ms 时间片、借鉴 requestIdleCallback」的说法属于上面这一层,出自第三方分析与旧演讲。要用这个数字,就一并写出处。

这张图是本站作者按上述社区模型画的,不是官方图。
和相邻几篇的关系
元素是什么,见 虚拟 DOM 与 React 元素;JSX 怎么变成函数调用,见 Babel 与 SWC;可中断的行为面,见 useTransition 与 useDeferredValue;Fiber 那一层的细节,见 React 的 Fiber 架构。
分享文章
生成精美分享图或复制链接,与更多人分享本文。
继续阅读
换条路线
从其他文章中稳定抽取
最后更新于 ,距今已过 191 天
部分内容可能已过时