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的渲染流程和性能优化策略。

相关推荐
幸运小圣1 小时前
LeetCode热题100-合并两个有序链表【JavaScript讲解】
javascript·leetcode·链表
我想学LINUX2 小时前
【2024年华为OD机试】 (C卷,100分)- 消消乐游戏(Java & JS & Python&C/C++)
java·c语言·javascript·c++·游戏·华为od
ฅQSω[*邱╭2 小时前
写个自己的vue-cli
前端·javascript·vue.js·学习
阿芯爱编程2 小时前
typescript语法讲解
前端·javascript
Daniel_1873 小时前
Promise-课堂笔记
前端·javascript·笔记
一点一木3 小时前
TensorFlow.js 和 Brain.js 全面对比:哪款 JavaScript AI 库更适合你?
前端·javascript·人工智能
疯狂的沙粒3 小时前
如何更轻松的对React refs 的理解?都有哪些应用场景?
前端·react.js·前端框架
w2sfot4 小时前
Building Real-Time APIs with Node.js and React.js Using Socket.io
前端·react.js·node.js
借来一夜星光5 小时前
【前端动效】原生js实现拖拽排课效果
前端·javascript·css3·html5
无限大.7 小时前
Vue 常用指令详解(附代码实例)
前端·javascript·vue.js