在组件显示在屏幕上之前,它们必须由 React 进行渲染。了解此过程中的步骤将帮助您思考代码的执行方式并解释其行为。
您将学习
- 渲染在 React 中的含义
- React 何时以及为何渲染组件
- 在屏幕上显示组件所涉及的步骤
- 为何渲染并不总是产生 DOM 更新
假设您的组件是厨房里的厨师,他们用食材烹饪美味佳肴。在这种情况下,React 就是服务员,接收顾客的点餐并为他们上菜。此 UI 请求和服务过程分为三个步骤:
- 触发渲染(将顾客的订单送到厨房)
- 渲染组件(在厨房准备订单)
- 提交到 DOM(将订单放在餐桌上)
插图作者 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
函数更新其状态来触发进一步的渲染。更新组件的状态会自动将其排入渲染队列。(您可以将这些想象成餐厅顾客在下第一个订单后,根据他们的口渴或饥饿程度,再点茶、甜点和各种东西。)
插图作者 Rachel Lee Nabors
步骤 2: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://i.imgur.com/ZF6s192.jpg" alt="'Floralis Genérica' by Eduardo Catalano: a gigantic metallic flower sculpture with reflective petals" /> ); }
- 在初始渲染期间,React 将会 创建 DOM 节点 用于
<section>
、<h1>
以及三个<img>
标签。 - 在重新渲染期间,React 将会计算自上次渲染以来,它们的哪些属性(如果有)发生了变化。它不会对这些信息进行任何处理,直到下一步,即提交阶段。
深入探讨
如果更新的组件在树中非常高,则渲染该组件中嵌套的所有组件的默认行为并不是性能最佳的。如果您遇到性能问题,“性能” 部分中描述了几种可选择的解决方法。不要过早优化!
步骤 3:React 将更改提交到 DOM
渲染(调用)您的组件后,React 将会修改 DOM。
- 对于初始渲染,React 将会使用
appendChild()
DOM API 将其创建的所有 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,浏览器将重新绘制屏幕。尽管此过程被称为“浏览器渲染”,但为了避免在整个文档中造成混淆,我们将其称为“绘制”。
插图作者 Rachel Lee Nabors