React-更新组件的三个阶段和源码解释

React 更新组件其实可以分为三个阶段:

  • Scheduler。任务优先级分配和调度
  • Render。更新组件内部状态,diff 计算 change
  • Commit。应用 change,执行副作用

Scheduler

该阶段主要是给任务分配优先级,统筹任务调度

Scheduler 的源码解析可以参考:https://juejin.cn/post/6889314677528985614

react 16 基于 requestIdleCallback 的 polyfill 方案来实现任务调度,用法如下:

window.requestIdleCallback(callback[, options])
let handle = window.requestIdleCallback((idleDeadline) => {
   
    const {
   didTimeout, timeRemaining} = idleDeadline;
    console.log(`是否超时?${
     didTimeout}`);
    console.log(`可用时间剩余${
     timeRemaining.call(idleDeadline)}ms`);
    // do sth
    const now = Date.now(), timespent = 10;
    while (Date.now() < now + timespent);
    console.log(`花了${
     timespent}ms`);
    console.log(`可用时间剩余${
     timeRemaining.call(idleDeadline)}ms`);
}, {
   timeout: 1000});
// 是否超时?false
// 可用时间剩余45ms
// 花了12ms
// 可用时间剩余32ms

由于 requestIdleCallback 有兼容问题,react 团队采用的是它的 polyfill 方案,可参考

  • https://www.zhuyuntao.cn/React%E4%B8%ADrequestIdleCallback%E7%9A%84polyfill%E5%AE%9E%E7%8E%B0
  • https://juejin.cn/post/6861590253434585096
react18
  • 更新时遍历更新每一个节点,每更新一个 Fiber 节点后,会判断累计更新时间是否超过 5ms。
  • 如果超过 5ms,将下一个更新创建为一个宏任务,浏览器自动为其分配执行时机,从而不阻塞用户事件等操作。
  • 如果更新的过程中,用户进行触发了点击事件,那么会在 5ms 与下一个 5ms 的间隙中去执行 click 事件回调

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Render

遍历 Fiber 树,得出需要更新的节点信息。可以被打断,让位于优先级更高的操作,比如用户点击等

  1. Fiber Root开始遍历,构建一个新的 Fiber 树。performSyncWorkOnRoot(root)–>renderRootSync
  2. 更新每个 fiber。workLoopSync–>performUnitOfWork–>beginWork
function workLoopSync() {
   
  // workInProgress:当前正在处理的节点
  while (workInProgress !== null) {
   
    performUnitOfWork(workInProgress);
  }
}

function performUnitOfWork(unitOfWork: Fiber): void {
   
  const current = unitOfWork.alternate;
  // ...
  // NOTE
  next = beginWork(current, unitOfWork, subtreeRenderLanes);
  // ...
  if (next === null) {
   
    // 如果没有子节点,则完成当前工作
    completeUnitOfWork(unitOfWork);
  } else {
   
    workInProgress = next;
  }
  ReactCurrentOwner.current = null;
}

beginWork 主要做了以下事情:

  1. 判断 fiber 节点是否可以复用
  2. 根据不同的 Tag(标记不同的组件类型:纯组件、函数组件、类组件),生成不同的 fiber 节点赋值给workInprogress.child
function beginWork(current, workInProgress, renderLanes) {
   
  // ...
  switch (workInProgress.tag) {
   
    // ...
    case FunctionComponent: {
   
      const Component = workInProgress.type;
      const unresolvedProps = workInProgress.pendingProps;
      const resolvedProps =
        workInProgress.elementType === Component
          ? unresolvedProps
          : resolveDefaultProps(Component, unresolvedProps);

      // NOTE
      return updateFunctionComponent(
        current,
        workInProgress,
        Component,
        resolvedProps,
        renderLanes,
      );
    }
    case ClassComponent: {
   
      const Component = workInProgress.type;
      const unresolvedProps = w
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值