React是如何工作的?

从编写组件到最后屏幕生成界面,如上图所示,我们现在需要知道的就是后面几步是如何运行的。

概述

这张图解释了 React 渲染过程的几个阶段:

  1. 渲染触发:通过更新某处的状态来触发渲染。
  2. 渲染阶段:React 调用组件函数,确定如何更新 DOM。这是内部计算阶段,不会立即对屏幕产生视觉变化。
  3. 提交阶段:React 实际写入 DOM,进行元素的更新、插入和删除。
  4. 浏览器绘制:浏览器将更新后的内容绘制到屏幕上。

在 React 中,渲染并不是指更新 DOM 或在屏幕上显示元素。渲染仅在 React 内部发生,不会直接产生视觉变化。

 渲染触发

渲染触发条件

  1. 初次渲染:应用程序的初始渲染。
  2. 状态更新:一个或多个组件实例的状态更新(重新渲染)。

直觉上的状态更新如下:

但其实并不是,实际上它是批量更新的。

例子如下:

关键点

  • 渲染过程是为整个应用程序触发的。
  • 实际上,看起来 React 只重新渲染状态更新的组件,但背后工作并非如此。
  • 渲染不会立即触发,而是安排在 JavaScript 引擎有空闲时间时执行。事件处理程序中的多个 setState 调用也会进行批处理。

渲染阶段

什么是虚拟DOM? 

它只是一个javascript对象。

为什么需要协调(Reconciliation)和区别(diffing)?

纤维树(Fiber tree)

React在内部维护了一个Fiber tree,用于存储每个组件的状态。当函数组件重新执行时,React会根据这个链表来恢复状态,而不是重新初始化。 

  • React 元素树(虚拟 DOM):左侧显示了一个 React 组件树,包含组件如 AppVideoModalOverlayh3 和 button。这是 React 的虚拟 DOM 表示。
  • Fiber 树:右侧是 Fiber 树,它在初次渲染时被创建。每个组件实例和 DOM 元素都有一个对应的“fiber”。
  • Fiber:每个 fiber 是一个“工作单元”,包含以下信息:
    • 当前状态
    • 属性(Props)
    • 副作用
    • 使用的钩子(hooks)
    • 工作队列
  • 纤维树的特点
    • 内部树结构:每个组件实例和DOM元素都有一个对应的“fiber”。这些fiber节点形成了一个树状结构,用于描述UI界面。
    • Fiber节点不在每次渲染时重新创建:这意味着React可以复用已有的fiber节点,从而减少不必要的计算和内存使用。
    • 异步渲染

      • 异步完成工作:Fiber允许将渲染任务分成小块,利用浏览器的空闲时间进行处理。这种方式避免了长时间阻塞主线程,提高了应用的响应性。
      • 任务优先级调度:React可以根据任务的重要性来决定执行顺序,优先处理用户交互等关键任务。
    • 并发特性

      • 支持并发特性:Fiber架构支持React中的并发模式,使得应用能够更好地处理复杂交互和动态变化,例如Suspense或过渡效果。
      • 长时间渲染不会阻塞JavaScript引擎:通过将渲染过程分割成小块,React能够在不中断用户界面的情况下进行更新。
    • 具体实现

      • 增量式渲染:通过将渲染任务分配到多个帧中,React可以保持应用的流畅性,即使在复杂布局或大量计算时也能保持响应。
      • 可中断和恢复的渲染:在需要时,React可以暂停当前任务,并在稍后恢复,从而提高用户体验。

 协调(Reconciliation)举例

 区分(Diffing)举例

key prop是什么?

在list中使用key prop

使用key prop重置状态 

这不是我们想要的,需要使用key prop进行重置state。

 提交阶段

绘制阶段

总结 

当React组件的state发生变化时,会触发组件的重新渲染。以下是详细过程:


1. 状态更新

当你调用setStateuseState的更新函数时,React会将新的状态值存入组件的状态中,并标记该组件为“需要更新”。


2. 调度重新渲染

React会将需要更新的组件加入更新队列,并安排一次重新渲染。React可能会批量处理多个状态更新,以减少不必要的渲染。当React调度重新渲染时,函数组件的内容会被重新执行一遍,在执行到如useState、useReducer、useContext等hook的时候,不会重新初始化,而是从 React 的内部存储中恢复之前的值。


3. 生成新的虚拟DOM

React会调用组件的render方法(类组件)或函数组件本身,生成新的虚拟DOM树。


4. Diff算法比较

React使用Diff算法比较新旧虚拟DOM树,找出需要更新的部分。比较规则包括:

  • 如果元素类型不同,直接替换整个子树。

  • 如果元素类型相同,更新变化的属性。

  • 对于列表元素,通过key属性识别元素,减少不必要的更新。


5. 更新真实DOM

React将虚拟DOM的差异应用到真实DOM上,只更新必要的部分,而不是重新渲染整个DOM树。


6. 调用生命周期方法或Hooks

  • 类组件

    • 如果实现了shouldComponentUpdate,React会调用它来决定是否跳过渲染。

    • 更新后会调用componentDidUpdate

  • 函数组件

    • 如果使用了useEffect,React会根据依赖项决定是否执行副作用。


7. 完成渲染

更新完成后,React会清理临时数据,并等待下一次状态或属性变化。


示例代码

function Counter() {
  const [count, setCount] = React.useState(0);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}
  • 点击按钮时,setCount会更新count状态。

  • React会重新渲染Counter组件,生成新的虚拟DOM。

  • 通过Diff算法,React发现只有<p>标签的内容发生了变化,因此只更新真实DOM中的文本内容。


性能优化

  • 避免不必要的渲染

    • 类组件:使用shouldComponentUpdateReact.PureComponent

    • 函数组件:使用React.memo

  • 减少状态更新频率

    • 使用useCallbackuseMemo缓存函数和值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值