react中render阶段做了什么

230 篇文章 1 订阅
30 篇文章 0 订阅

首先说明一个概念:
render阶段对应的是Reconciler(协调器),
commit阶段对应的的是Renderer(渲染器)

render阶段开始于performSyncWorkOnRoot或performConcurrentWorkOnRoot方法的调用。这取决于本次更新是同步更新还是异步更新。

// performSyncWorkOnRoot会调用该方法
function workLoopSync() {
  while (workInProgress !== null) {
    performUnitOfWork(workInProgress);
  }
}

// performConcurrentWorkOnRoot会调用该方法
function workLoopConcurrent() {
  while (workInProgress !== null && !shouldYield()) {
    performUnitOfWork(workInProgress);
  }
}

我们知道Fiber Reconciler是从Stack Reconciler重构而来,通过遍历的方式实现可中断的递归,所以performUnitOfWork的工作可以分为两部分:“递”和“归”。

“递”阶段

首先从rootFiber开始向下深度优先遍历,为遍历到的每个Fiber节点调用beginWork 方法。
该方法会根据传入的Fiber节点创建子Fiber节点,并将这两个Fiber节点连接起来。
当遍历到叶子节点(即没有子组件的组件)时就会进入“归”阶段。
effectTag:
也会做一些标记,这个标记主要和元素的位置有关系。

// DOM需要插入到页面中
export const Placement = /*                */ 0b00000000000010;
// DOM需要更新
export const Update = /*                   */ 0b00000000000100;
// DOM需要插入到页面中并更新
export const PlacementAndUpdate = /*       */ 0b00000000000110;
// DOM需要删除
export const Deletion = /*                 */ 0b00000000001000;

“归”阶段:

  • 为Fiber节点生成对应的DOM节点
  • 将子孙DOM节点插入刚生成的DOM节点中
// mount的情况

// ...省略服务端渲染相关逻辑

const currentHostContext = getHostContext();
// 为fiber创建对应DOM节点
const instance = createInstance(
  type,
  newProps,
  rootContainerInstance,
  currentHostContext,
  workInProgress
);
// 将子孙DOM节点插入刚生成的DOM节点中
appendAllChildren(instance, workInProgress, false, false);
// DOM节点赋值给fiber.stateNode
workInProgress.stateNode = instance;

// 与update逻辑中的updateHostComponent类似的处理props的过程
if (
  finalizeInitialChildren(
    instance,
    type,
    newProps,
    rootContainerInstance,
    currentHostContext
  )
) {
  markUpdate(workInProgress);
}

那么commit阶段是如何通过一次插入DOM操作(对应一个Placement effectTag)将整棵DOM树插入页面的呢?

原因就在于completeWork中的appendAllChildren方法。

由于completeWork属于“归”阶段调用的函数,每次调用appendAllChildren时都会将已生成的子孙DOM节点插入当前生成的DOM节点下。那么当“归”到rootFiber时,我们已经有一个构建好的离屏DOM树。
EffectList:
至此render阶段的绝大部分工作就完成了。

还有一个问题:作为DOM操作的依据,commit阶段需要找到所有有effectTag的Fiber节点并依次执行effectTag对应操作。难道需要在commit阶段再遍历一次Fiber树寻找effectTag !== null的Fiber节点么?

这显然是很低效的。

为了解决这个问题,在completeWork的上层函数completeUnitOfWork中,每个执行完completeWork且存在effectTag的Fiber节点会被保存在一条被称为effectList的单向链表中。

effectList中第一个Fiber节点保存在fiber.firstEffect,最后一个元素保存在fiber.lastEffect。

类似appendAllChildren,在“归”阶段,所有有effectTag的Fiber节点都会被追加在effectList中,最终形成一条以rootFiber.firstEffect为起点的单向链表。

                      nextEffect         nextEffect
rootFiber.firstEffect -----------> fiber -----------> fiber

这样,在commit阶段只需要遍历effectList就能执行所有effect了。

### 回答1: 在 react commit 阶段React执行以下操作: - 调用组件的 `render()` 方法来获取组件的虚拟 DOM(virtual DOM) - 对比上一次渲染的虚拟 DOM 和当前虚拟 DOM,找出它们之间的差异 - 打补丁,将差异应用到真实 DOM 上,使真实 DOM 与虚拟 DOM 保持同步 除了 commit 阶段React 还有以下几个阶段: - render 阶段:调用组件的 `render()` 方法,获取组件的虚拟 DOM - reconcile 阶段:对比上一次渲染的虚拟 DOM 和当前虚拟 DOM,找出它们之间的差异 - commit 阶段:打补丁,将差异应用到真实 DOM 上,使真实 DOM 与虚拟 DOM 保持同步 ### 回答2: 在React,commit阶段React更新DOM并进行最终渲染的阶段。在commit阶段React通过协调更新队列的任务,将变化应用到实际的DOM树上。 具体来说,commit阶段主要完成以下任务: 1. 生成DOM更新:在commit阶段React会将变化转换为具体的DOM操作。这包括创建、更新和删除DOM节点等。 2. 调用生命周期方法:在更新DOM之前,React会调用组件的生命周期方法,例如`componentDidMount`或`componentDidUpdate`。这样,开发者可以在这些方法执行一些副作用或处理逻辑,例如发送网络请求、订阅事件等。 3. 处理副作用:在commit阶段React还会处理一些副作用操作,例如更新refs、触发组件的回调函数、处理错误边界等。 除了commit阶段React还有其他几个重要的阶段: 1. 事件处理阶段:在这个阶段React会收集和处理用户的事件,并将事件传递给相应的组件。这包括事件捕获、冒泡、合成事件的处理等。 2. 虚拟DOM的构建阶段:在这个阶段React会根据组件的状态变化,生成新的虚拟DOM树。React通过对比新旧虚拟DOM树的差异,减少对实际DOM的操作。 3. 调解阶段:在这个阶段React会根据组件的更新情况,决定是否要进行组件的更新。React使用一些策略,例如shouldComponentUpdate或memo来进行性能优化,避免不必要的更新。 4. 协调阶段:在这个阶段React会协调处理多个组件的更新。它通过批处理更新任务,将相似或相关的更新合并在一起,减少不必要的计算和渲染。 总之,React的commit阶段是实际将变化应用到DOM的阶段,同时React还有其他阶段用于处理事件、构建虚拟DOM、调解和协调组件的更新。 ### 回答3: 在 React ,commit 阶段是用于将虚拟 DOM 更新应用到实际的 DOM 上的阶段。在 commit 阶段React执行以下操作: 1. 执行必要的 DOM 操作:根据虚拟 DOM 的变化,React 将添加、更新或删除相应的 DOM 节点。 2. 触发组件的副作用操作:在 React ,副作用操作指的是那些不直接与渲染相关,但仍然需要在组件渲染后进行的任务,例如发起网络请求、订阅事件等。在 commit 阶段React 将触发组件声明的副作用操作。 3. 运行生命周期方法:在组件更新完成并且 DOM 更新后,React 会运行相应组件实例的生命周期方法,例如 componentDidUpdate。 除了 commit 阶段React 还有其他几个重要的阶段: 1. 渲染阶段render phase):在渲染阶段React 会比对组件的新旧状态并生成虚拟 DOM。这个阶段的主要目标是计算变更,而不会实际应用这些变更。 2. 调度阶段(scheduling phase):在调度阶段React 会根据当前系统的优先级决定是否断渲染过程,以便让用户交互或其他高优先级任务得到处理。这个阶段采用了一种称为 Fiber 的机制,用于实现可断的渲染过程。 3. 布局阶段(layout phase):在布局阶段React 会计算出虚拟 DOM 在浏览器的位置和尺寸。这个阶段的主要目标是收集有关 DOM 树结构的信息,以便在下一阶段进行 DOM 更新。 4. 提交阶段(commit phase):如前所述,提交阶段是将虚拟 DOM 更新应用到实际的 DOM 上的阶段。 总结起来,React 的渲染过程可以分为调度阶段、渲染阶段、布局阶段和提交阶段。其,commit 阶段是将虚拟 DOM 的更新应用到实际 DOM 上的阶段,还包括执行 DOM 操作、触发副作用操作和运行生命周期方法等任务。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值