源码分析之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. 处理并发模式下的更新冲突
相关推荐
Mr Xu_2 小时前
Vue + Element Plus 实现前端导出 Excel 功能详解
前端·javascript·vue.js
仰泳之鹅2 小时前
【杂谈】使用Edge浏览器下载文件显示“Microsoft Defender SmartScreen 已阻止此不安全文件”的解决方法
前端·edge
万邦科技Lafite3 小时前
小红书评论数据一键获取,item_reviewAPI接口讲解
大数据·前端·数据库·chrome·电商开放平台
meng半颗糖4 小时前
vue3+tpescript 点击按钮跳转新页面直接通过链接预览word
前端·vue.js·word
击败不可能4 小时前
vue做任务工具方法的实现
前端·javascript·vue.js
觉醒大王4 小时前
医学好投的普刊分享
前端·论文阅读·深度学习·学习·自然语言处理·学习方法
小二·4 小时前
Python Web 开发进阶实战:AI 编排引擎 —— 在 Flask + Vue 中构建低代码机器学习工作流平台
前端·人工智能·python
【赫兹威客】浩哥4 小时前
【赫兹威客】框架模板-前端bat脚本部署教程
前端·vue.js
sww_10264 小时前
智能问数系统(二):数据分析师Python
java·前端·python