在你的组件显示到屏幕之前,它们必须先由 React 渲染。理解这个过程中的各个步骤,将帮助你思考代码是如何执行的,并解释它的行为。
You will learn
- React 中“渲染”是什么意思
- React 何时以及为什么会渲染组件
- 在屏幕上显示组件所涉及的步骤
- 为什么渲染不一定会产生 DOM 更新
想象你的组件是厨房里的厨师,用各种食材准备美味菜肴。在这个场景中,React 就是服务员,负责接收顾客的请求并把订单送达。这个请求和提供 UI 的过程分为三步:
- 触发 渲染(把客人的订单送到厨房)
- 渲染 组件(在厨房里准备订单)
- 提交 到 DOM(把订单放到桌上)

触发 
渲染 
提交
Illustrated by Rachel Lee Nabors
第 1 步:触发渲染
组件需要渲染有两个原因:
- 它的 初始渲染。
- 该组件(或其某个祖先组件)的 状态已更新。
初始渲染
当你的应用启动时,你需要触发初始渲染。框架和沙盒有时会隐藏这段代码,但本质上是通过对目标 DOM 节点调用 createRoot,然后使用你的组件调用它的 render 方法来完成的:
import Image from './Image.js'; import { createRoot } from 'react-dom/client'; const root = createRoot(document.getElementById('root')) root.render(<Image />);
试着把 root.render() 调用注释掉,看看组件是否会消失!
状态更新时的重新渲染
一旦组件完成了初始渲染,你就可以通过使用 set 函数。 更新它的状态来触发后续渲染。更新组件的状态会自动把一次渲染排入队列。(你可以把它想象成餐厅里的客人在点完第一单后,又根据自己是渴还是饿,继续点茶、甜点以及各种各样的东西。)

状态更新... 
...触发... 
...渲染!
Illustrated by Rachel Lee Nabors
第 2 步:React 渲染你的组件
当你触发渲染后,React 会调用你的组件来弄清楚屏幕上应该显示什么。“渲染”就是 React 调用你的组件。
- 在初始渲染时, React 会调用根组件。
- 在后续渲染时, React 会调用触发了这次渲染的那个函数组件。
这个过程是递归的:如果更新后的组件返回了另一个组件,React 接下来就会渲染那个组件;如果那个组件也返回了别的东西,React 接着就会渲染那个组件,依此类推。这个过程会一直持续,直到不再有嵌套组件,React 也就能准确知道屏幕上应该显示什么。
在下面的示例中,React 会多次调用 Gallery() 和 Image():
export default function Gallery() { return ( <section> <h1>Inspiring Sculptures</h1> <Image /> <Image /> <Image /> </section> ); } function Image() { return ( <img src="https://react.dev/images/docs/scientists/ZF6s192.jpg" alt="'Floralis Genérica' by Eduardo Catalano: a gigantic metallic flower sculpture with reflective petals" /> ); }
- 在初始渲染期间, React 会为
<section>、<h1>和三个<img>标签 创建 DOM 节点。 - 在重新渲染期间, React 会计算它们的哪些属性(如果有)自上一次渲染以来发生了变化。直到下一步,即提交阶段,它才会使用这些信息。
Deep Dive
默认情况下,渲染更新组件内部所有嵌套组件的行为,在更新组件处于树的较高位置时,对性能并不理想。如果你遇到性能问题,可以在 性能 章节中找到几种可选的解决方式。不要过早优化!
第 3 步:React 将变更提交到 DOM
在渲染(调用)完你的组件后,React 会修改 DOM。
- 对于初始渲染, React 会使用 DOM API
appendChild()将它创建的所有 DOM 节点放到屏幕上。 - 对于重新渲染, React 会应用必要的最小操作(在渲染时计算得出!),使 DOM 与最新的渲染输出保持一致。
只有当两次渲染之间存在差异时,React 才会改变 DOM 节点。 例如,下面这个组件每秒都会从其父组件接收不同的 props 并重新渲染。注意,你可以向 <input> 中输入一些文本,更新它的 value,但当组件重新渲染时,文本并不会消失:
export default function Clock({ time }) { return ( <> <h1>{time}</h1> <input /> </> ); }
这之所以有效,是因为在最后这一步中,React 只会用新的 time 更新 <h1> 的内容。它发现 <input> 在 JSX 中出现的位置和上一次相同,所以 React 不会碰 <input>——也不会碰它的 value!
尾声:浏览器绘制
在渲染完成且 React 更新了 DOM 之后,浏览器会重新绘制屏幕。虽然这个过程被称为“浏览器渲染”,但为了避免在本文档中产生混淆,我们会把它称为“绘制”。

Illustrated by Rachel Lee Nabors