React Fiber框架中的Commit提交阶段——commitMutationEffect函数

Render阶段

Render阶段可大致归为beginWork(递)和completeWork(归)两个阶段
1.beginWork流程(递)

  1. 建立节点的父子以及兄弟节点关联关系
    child return sibling属性
  2. 给fiber节点打上flag标记(当前节点的flag)
    渲染阶段结束fiberRootNode.finishwork=wip,进入就断除
    2.completeWork流程(归)

主要执行任务:

1.创建真实dom节点,但是仍在内存中,未渲染到页面

2.处理flag与subtreeFlags标记子树标识,用"|" 运算处理)

3.建立真实DOM关系,将子元素插入父元素中

completeWork归工作完成,将建立fiberRootNode.finishWork=wip关系,当然进入
Commit阶段

  1. commit工作前又会断掉此关系。(状态机,标识运行状态)
  2. 当commitMutationEffect(commit执行完),将dom渲染到页面中之后
    root.current=finishedWork断开和老节点的联系指向新节点


bash 复制代码
function commitRoot(root:FiberRootNode){
	const finishedwork =root.finishedwork;
	if(finishedwork === null){
		return;
	}
	console.log('commit阶段开始',finishedwork);
	root.finishedwork=null;
	//判断是否存在3个子阶段需要执行的造作
	// root flags root subtreerlags
	const subtreeHaseffect=
	(finishedwork.subtreeFlags & MutationMask)!== NoFlags;
	const rootHasEffect:(finishedwork,flags & MutationMask) !== NoFlags;
	if(subtreeHasEffectrootHasEffect){
		// beforeMutation
		//mutation placement
		commitMutationEffects(finishedwork);
		root.current =finishedwork;
		// layout
	}else {
		root.current =finishedwork;
	}
  • 在渲染阶段的completeWork函数中已经构建真实DOM的关系,并对fiber树的每个节点进行了标识。标识包括两部分,一个是flag标识当前节点是否有DOM副作用操作,另一个就是subtreeFlag标识当前节点的子树是否有DOM副作用操作
  • 巧妙的双flag ,后续更改,虚拟DOM跟着有关?

commitMutationEffects函数详解

在React的Fiber架构中,commitMutationEffects是一个内部函数,负责在"commit"阶段的"mutation"子阶段中执行DOM更新。这个函数是React渲染流程中的关键一环,它确保了React组件的状态变更能够正确地反映到真实的DOM结构上。

javascript 复制代码
function commitMutationEffects(root, finishedWork, committedLanes) {
  let nextEffect = finishedWork;

  // 遍历 Fiber 树,处理副作用
  while (nextEffect !== null) {
    const deletions = nextEffect.deletions;
    if (deletions !== null) {
      for (let i = 0; i < deletions.length; i++) {
        const childToDelete = deletions[i];
        commitDeletion(root, childToDelete);
      }
    }

    if (nextEffect.subtreeFlags & MutationMask) {
      const child = nextEffect.child;
      if (child !== null) {
        child.return = nextEffect;
        nextEffect = child;
        continue;
      }
    }
    commitMutationEffectsOnFiber(nextEffect, root, committedLanes);

    const sibling = nextEffect.sibling;
    if (sibling !== null) {
      sibling.return = nextEffect.return;
      nextEffect = sibling;
      continue;
    }

    nextEffect = nextEffect.return;
  }
}

function commitMutationEffectsOnFiber(finishedWork, root, committedLanes) {
  const flags = finishedWork.flags;

  // 插入新节点
  if (flags & Placement) {
    commitPlacement(finishedWork);
    finishedWork.flags &= ~Placement; // 清除 Placement 标记
  }

  // 更新节点
  if (flags & Update) {
    commitUpdate(finishedWork);
  }

  // 删除节点
  if (flags & Deletion) {
    commitDeletion(root, finishedWork);
  }

  // 处理 refs
  if (flags & Ref) {
    commitAttachRef(finishedWork);
  }
}
function commitPlacement(finishedWork) {
  const parentFiber = getHostParentFiber(finishedWork);
  const parent = getHostParent(parentFiber);

  if (parent !== null) {
    const before = getHostSibling(finishedWork);
    appendChildToContainer(parent, finishedWork.stateNode, before);
  }
}

function commitDeletion(root, childToDelete) {
  // 清理 refs
  if (childToDelete.flags & Ref) {
    commitDetachRef(childToDelete);
  }

  // 卸载子组件
  unmountHostComponents(childToDelete);

  // 如果节点有副作用清理函数,执行它们
  const alternate = childToDelete.alternate;
  if (alternate !== null) {
    const finishedEffect = alternate.lastEffect;
    if (finishedEffect !== null) {
      // 执行 Effect 的销毁函数
      commitPassiveUnmountEffects(finishedEffect);
    }
  }
}

commitMutationEffects的作用

commitMutationEffects的主要任务是遍历Fiber树中的effect list(副作用列表),并执行与DOM操作相关的副作用。这些副作用可能包括:

  • 插入新元素:当React组件被添加到DOM中时,需要创建新的DOM节点并将其插入到正确的位置。
  • 删除旧元素:当React组件被移除时,需要从DOM中删除对应的节点。
  • 更新元素属性:当React组件的属性(props)或状态(state)发生变化时,需要更新DOM节点的属性以反映这些变化。
  • 文本内容更新:对于文本节点,当文本内容发生变化时,需要更新DOM节点的文本内容。

执行过程

在执行commitMutationEffects时,React会按照Fiber树的遍历顺序,逐个处理effect list中的每个effect。对于每个effect,React会根据其类型(如插入、删除、更新等)执行相应的DOM操作。

  • 遍历 Fiber 树
    React 使用深度优先的方式遍历 Fiber 树,对每一个 Fiber 节点检查是否有需要执行的副作用(Effect)。
  • 处理不同的副作用标记
    每个 Fiber 节点有一个 flags 属性,表示需要处理的副作用类型。在 commitMutationEffectsOnFiber 中,处理了以下常见的 flags:
    • Placement: 表示需要将节点插入 DOM。
    • Update: 表示节点属性或样式更新。
    • Deletion: 表示需要从 DOM 中移除节点。
  • 特殊处理
    某些类型的节点(如 Class 组件和函数组件)需要处理额外的逻辑,例如:
    • 调用生命周期方法(如 componentWillUnmount)。
    • 清理资源(如 Effect 的销毁函数)。
  • 递归子节点
    在处理完当前节点的副作用后,继续递归处理其子节点,直到整个 Fiber 树被遍历完成。

注意事项

  • 不可中断性 :与render阶段不同,commit阶段是同步且不可中断的。这意味着一旦开始执行commitMutationEffects,它将一直执行到完成,而不会被其他任务中断。
  • 性能优化 :尽管commit阶段需要执行DOM操作,但React通过一些优化策略来减少不必要的DOM更新。例如,React使用虚拟DOM来比较新旧Fiber树之间的差异,并只更新那些实际发生变化的DOM节点
  • 副作用处理 :除了DOM操作外,commitMutationEffects还可能处理其他类型的副作用,如类组件的生命周期方法调用(如componentDidUpdate)和函数组件的useEffect回调执行。然而,这些副作用通常会在commit阶段的不同子阶段中处理。

关键点说明

  1. 标记系统(Flags): React 使用 flags 属性来标记需要处理的副作用,比如

    Placement、Update、Deletion。

  2. 子树标记(SubtreeFlags): subtreeFlags 用于快速判断某个子树是否有副作用,可以跳过不需要处理的部分。

  3. 递归与遍历: nextEffect 的遍历逻辑是 React 树递归的重要模式,支持深度优先遍历整个 Fiber 树。

  4. 辅助函数: 像 commitPlacement、commitUpdate 和 commitDeletion

    是副作用执行的关键,它们最终会操作 DOM 或调用组件的生命

周期方法。

总结

commitMutationEffects是React Fiber架构中负责执行DOM更新的关键函数。它确保了React组件的状态变更能够正确地反映到真实的DOM结构上,并通过一些优化策略来提高性能。了解这个函数的工作原理有助于深入理解React的渲染流程和性能优化策略。

相关推荐
随笔记10 分钟前
react-router里的两种路由方式有什么不同
前端·react.js
前端李二牛10 分钟前
异步任务并发控制
前端·javascript
你也向往长安城吗31 分钟前
推荐一个三维导航库:three-pathfinding-3d
javascript·算法
karrigan41 分钟前
async/await 的优雅外衣下:Generator 的核心原理与 JavaScript 执行引擎的精细管理
javascript
wycode1 小时前
Vue2实践(3)之用component做一个动态表单(二)
前端·javascript·vue.js
wycode2 小时前
Vue2实践(2)之用component做一个动态表单(一)
前端·javascript·vue.js
第七种黄昏2 小时前
Vue3 中的 ref、模板引用和 defineExpose 详解
前端·javascript·vue.js
我是哈哈hh2 小时前
【Node.js】ECMAScript标准 以及 npm安装
开发语言·前端·javascript·node.js
张元清3 小时前
电商 Feeds 流缓存策略:Temu vs 拼多多的技术选择
前端·javascript·面试
晴空雨3 小时前
React 合成事件原理:从事件委托到 React 17 的重大改进
前端·react.js