源码分析之React中updateContainerImpl方法更新容器

概览

ReactDOMRootrenderunmount方法中均调用了updateContainerImpl方法,该方法是React中更新容器的核心方法,负责创建和调度更新。

源码分析

updateContainerImpl

updateContainerImpl方法源码实现如下:

js 复制代码
function updateContainerImpl(
  rootFiber, //根Fiber节点
  lane, // 更新优先级
  element, //要渲染的React元素
  container, // Fiber根节点容器
  parentComponent, // 父组件
  callback // 更新完成后的回调函数
) {
  // 获取子树的上下文,会返回一个空对象
  parentComponent = getContextForSubtree(parentComponent);
  // 若Fiber根节点容器上下文为空,则设置其为获取到的上下文(空对象);否则设置待处理的上下文为空对象
  null === container.context
    ? (container.context = parentComponent)
    : (container.pendingContext = parentComponent);
  // 根据优先级车道创键更新对象  
  container = createUpdate(lane);
  // 将要渲染的React元素作为更新对像的载荷
  container.payload = { element: element };

  // 若回调未定义,则设为null,否则保留原值
  callback = void 0 === callback ? null : callback;
  // 若回调不为null,则将其设为更新对象的callback属性值
  null !== callback && (container.callback = callback);
  
  // 将更新对象添加到Fiber节点的更新队列,并获取FiberRoot
  element = enqueueUpdate(rootFiber, container, lane);

  // 判断 若返回的更新对象不为null,则调度更新
  null !== element &&
    (scheduleUpdateOnFiber(element, rootFiber, lane),
    entangleTransitions(element, rootFiber, lane));
}

createUpdate

createUpdate接受一个参数车道优先级(lane),返回一个更新对象,其对象类型为UpdateUpdate会被放入更新队列中等待调度执行,其优先级为参数lanetagUpdateState:0,其实现如下:

js 复制代码
function createUpdate(lane){
  return {
    lane: lane,  // 更新优先级
    tag: UpdateState, // 其值为1 ,表示更新类型
    payload: null, // 更新载荷
    callback: null, // 回调函数
    next: null // 指向下一个更新
  }
}

enqueueUpdate

enqueueUpdate方法用于将更新对象加入Fiber节点的更新队列,其源码实现如下:

js 复制代码
function enqueueUpdate(fiber, update, lane) {
  // 获取Fiber节点上的更新队列updateQueue
  var updateQueue = fiber.updateQueue;
  // 若更新队列为空,则返回null,此时Fiber节点已被卸载
  if (null === updateQueue) return null;
  // 获取共享队列
  updateQueue = updateQueue.shared;

  // 检查是否是渲染更新阶段
  if (0 !== (executionContext & 2)) {
    // 获取共享队列的最后一个节点
    var pending = updateQueue.pending;
    // 判断最后一个节点是否为空
    null === pending
      ? (update.next = update) // 将更新对象update的next指向自身
      : ((update.next = pending.next), (pending.next = update)); //否则将更新对象的next指向最后一个节点的next,并且将最后一个节点的next指向更新对象,即将更新对象插入到环形链表的末尾
    // 更新pending指针  
    updateQueue.pending = update;
    // 从Fiber节点中获取FiberRoot
    update = getRootForUpdatedFiber(fiber);
    // 标记fiber节点中的优先级
    markUpdateLaneFromFiberToRoot(fiber, null, lane);
    // 最后返回FiberRoot
    return update;
  }
  // 若不是渲染更新阶段,则依次执行enqueueUpdate$1,getRootForUpdatedFiber,最后返回getRootForUpdatedFiber的结果FiberRoot
  // 调用enqueueUpdate$1方法就是将相关参数放到并发队列concurrentQueues中
  enqueueUpdate$1(fiber, updateQueue, update, lane);
  return getRootForUpdatedFiber(fiber);
}

getRootForUpdatedFiber

Fiber节点的return始终是指向父节点,因此通过不断追溯return可以找到根节点;

js 复制代码
function getRootForUpdatedFiber(sourceFiber) {
  // 判断某计数器,暂且不提
  if (50 < nestedUpdateCount)
    throw (
      ((nestedUpdateCount = 0),
      (rootWithNestedUpdates = null),
      Error(formatProdErrorMessage(185)))
    );
  for (var parent = sourceFiber.return; null !== parent; )
    (sourceFiber = parent), (parent = sourceFiber.return);
  
  // 判断当前Fiber节点的根节点类型是否为HostRoot,若是,则返回其DOM元素,否则返回null
  return 3 === sourceFiber.tag ? sourceFiber.stateNode : null;
}

scheduleUpdateOnFiber

调用enqueueUpdate方法更新相关队列后,会拿到FiberRoot,若FiberRoot不为null,则调用scheduleUpdateOnFiber进行调度更新。

entangleTransitions

entangleTranslations方法用于纠缠过渡更新,主要有3个作用:

  1. 将当前更新与正在进行的过渡更新纠缠
  2. 确保过渡更新的正确顺序
  3. 处理并发模式下的更新冲突
相关推荐
醇氧39 分钟前
CountDownLatch / CyclicBarrier / Semaphore 面试高频问答清单
前端·面试·职场和发展
qetfw2 小时前
MXU:Tauri 2 + React 的 MaaFramework 跨平台 GUI 源码
前端·python·react.js·前端框架·开源项目·效率工具
甲维斯2 小时前
我要开始吹牛逼了!Kimi K3 “宇宙无敌”!
前端·人工智能
a1117762 小时前
微光小屋-前端养成小游戏 开源项目
前端
kyriewen2 小时前
我让AI给前端项目做了一次完整的Code Review——它和人类的差距,比我想的大得多
前端·javascript·ai编程
张鑫旭2 小时前
快速过下我2026年上半年的前端学了些啥
前端
এ慕ོ冬℘゜3 小时前
前端基础:什么是时间戳?JS获取时间戳三种方法与实战用途
开发语言·前端·javascript
hoLzwEge3 小时前
拯救低效调试!code-inspector-plugin 让代码定位如虎添翼
前端·前端框架·node.js