likes
comments
collection
share

🔥【图解 React】🚀Vue 转 React 必备🚀(二)React 18 重渲染市面上的某些源码解析,没有一个

作者站长头像
站长
· 阅读数 57

前言

  • 市面上的某些源码解析,没有一个真实的案例把整个 react 流程串起来。导致看了许多所谓的源码,反而把自己看懵了
  • 所以本系列文章全部从实际案例出发,尽力让零基础未接触 React 的人都能上手源码
  • 本人在未做过 react 项目的前提下先学的源码,所以各位大神应该可以无痛上手

如果有帮忙到的请帮忙给小弟点赞收藏,非常感谢!

🤖 代码实例

流程图地址 www.processon.com/v/66d7cbac4…

<html lang="en">
  <body>
    <div id="root"></div>
  </body>
</html>
function App() {
  const [state, setState] = useState(true);
  function handleClick() {
    setState(pre => !pre)
  }
    
  return <div onClick={handleClick}>
    {
       state ? <Son/> : <Daughter />
    }
         </div>       
}    
    
function Son() {
    return <div id={'son'}></div>
}
    
function Daughter() {
    return <div id={"Daughter"}></div>
}

🤖 点击 <div onClick={handleClick}/>

🚀 调用 setState(false),触发重渲染

function setState(value) {
  
  1. 创建一个更新
  const update =  {
    action: value
  }

  2. 触发重渲染,应用更新于当前 fiber 树,产生新的 fiber 树
  scheduleUpdateOnFiber()
}

🤖 render 阶段

🚀 创建新 fiber 树的第一个节点

  • 诶? 当前页面对应的 fiber 树的 alternate 属性刚好是一个 fiber 节点
  • 不用白不用,刚好作为新 fiber 树的第一个节点
  • 顺便把当前页面的 HostRootFiber 上的属性浅拷贝给我 注意:由于浅拷贝了,所以我的 fiber.child 指向了当前的 <App /> Fiber 🔥【图解 React】🚀Vue 转 React 必备🚀(二)React 18 重渲染市面上的某些源码解析,没有一个

🚀 由上往下对每个 fiber 执行 beginWork

  • HostRootFiber 执行 beginWork
function beginWork() {
  if (函数组件新旧属性一样 && 函数组件没有执行过 setState) {
    1. 复用当前页面的子节点,也就是 <App /> Fiber // const (新 <App /> Fiber) = cloneFiber(fiber.child) // 看第一张图红色的线
    // 复用的意思,创建一个新的 <App /> Fiber,但是他的属性是浅拷贝旧 <App /> Fiber 的
    2. return <App /> Fiber  
  }
  ...
}

🔥【图解 React】🚀Vue 转 React 必备🚀(二)React 18 重渲染市面上的某些源码解析,没有一个

  • App Fiber 执行 beginWork
  • 重新执行了 App 组件的函数,所以 App 就是重渲染 React 浏览器插件可以看到这个 <App /> 组件闪了一下红色
function beginWork() { 
   //  <App /> 执行过 setState,不进入这个逻辑
   if (函数组件新旧属性一样 && 函数组件没有执行过 setState) {}
  
  switch (fiber.tag) {
    case FunctionComponent: {
      1. 重新执行函数组件(fiber.type),重新执行 useState, 拿到最新值 state =
      false, 重新执行 __jsx("div",...), 拿到新的 div JSX
      // function App() {
      //   const [state, setState] = useState(true);  
      //   return _jsx("div", {
      //     onClick: handleClick,
      //     children: state ? _jsx(Son, {}) : _jsx(Daughter, {})
      //   });
      // }
      2. div jsx 跟 当前页面的 Fiber 进行 dom-diff, 都是 div,复用 div Fiber
      
      3. 返回 Div Fiber
    }
  }
}

下一篇:useState 怎么拿到最新值?

🔥【图解 React】🚀Vue 转 React 必备🚀(二)React 18 重渲染市面上的某些源码解析,没有一个

  • div Fiber 执行 beginWork
function beginWork() { 
   //<App /> 函数重新执行,导致重新执行 _jsx(), 导致 div 的 props 属性变了,不进入这个逻辑
   if (函数组件新旧属性一样 && 函数组件没有执行过 setState) {}
  
  switch (fiber.tag) {
    case HostComponent: {
      1. 拿到 div fiber 的 pendingProps.children,也就是 <Daughter /> JSX
      2. <Daughter /> JSX 跟 <Son /> Fiber 比较,type 不同,不能复用
      3. <App /> Fiber 标记 ChildDeletion 副作用,并把 <Son /> fiber 放到 <App /> 的 deletions 数组里
      4. 创建新的 <Daughter /> Fiber,标记 Placement 副作用 
      5. return <Daughter /> Fiber
    }
  }
}

🔥【图解 React】🚀Vue 转 React 必备🚀(二)React 18 重渲染市面上的某些源码解析,没有一个

  • Daughter Fiber 执行 beginWork
function beginWork() { 
   //<App /> 函数重新执行,导致重新执行 _jsx(Daughter, {}), 导致 div 的 props 属性变了,不进入这个逻辑
   if (函数组件新旧属性一样 && 函数组件没有执行过 setState) {}
  
  switch (fiber.tag) {
    case FunctionComponent: {
      1.拿到函数组件本身(fiber.type)执行,拿到返回的 <div/> jsx
      2.创建新的 <div /> Fiber
      3.return  <div/> Fiber
    }
  }
}

🔥【图解 React】🚀Vue 转 React 必备🚀(二)React 18 重渲染市面上的某些源码解析,没有一个

🚀 走到 fiber 树最深处,又由下往上对每个 fiber 执行 completeWork

  • Div fiber 执行 completeWork
function completeWork() {
  switch (fiber.tag) {
    case HostComponent: {
      // <div /> Fiber 新创建的,当前页面没有对应的 Fiber,所以直接创建
      1.通过 document.createElement("div") 【fiber.type】 创建 div dom 节点
      2.fiber 上的 stateNode 属性和 div dom 节点相关联
    }        
  }  
}

🔥【图解 React】🚀Vue 转 React 必备🚀(二)React 18 重渲染市面上的某些源码解析,没有一个

  • <Daughter/> fiber 执行 completeWork,没做啥,省略

  • Div fiber 执行 completeWork

function completeWork() {
  switch (fiber.tag) {
    case HostComponent: {
      // 当前的 <div /> Fiber 上已经有 stateNode 了
      对比 div 的新旧属性差异,如果有,还会给 <div /> Fiber 标记 Update 副作用
      这里新旧属性props里面的值没有变化,所以没有标记 Update 副作用
    }        
  }  
}
  • App fiber 执行 completeWork,没做啥,省略
  • HostRootFiber fiber 执行 completeWork,没做啥,省略

🤖 commit 阶段

  • HostRootFiber Fiber 执行 commitMutationEffectsOnFiber
function commitMutationEffectsOnFiber() {
  switch (fiber.tag) {
    case HostRoot: {
    
      // 递归函数: 里面先对子 <App /> Fiber 执行 commitMutationEffectsOnFiber
      recursivelyTraverseMutationEffects()
        
      // 递归完,才处理 HostRootFiber Fiber 自己,这里暂时没做什么
      commitReconciliationEffects() 
    }
  }
}
  • App Fiber 执行 commitMutationEffectsOnFiber
function commitMutationEffectsOnFiber() {
  switch (fiber.tag) {
    case FunctionComponent: {
    
      // 递归函数: 里面先对子 <div /> Fiber 执行 commitMutationEffectsOnFiber
      recursivelyTraverseMutationEffects()
        
      // 递归完,才处理 <App /> Fiber 自己,这里暂时没做什么
      commitReconciliationEffects() 
    }
  }
}
  • <div /> Fiber 执行 commitMutationEffectsOnFiber
  • 应用 ChildDeletion 副作用,卸载真实的旧的 dom 节点
function commitMutationEffectsOnFiber() {
  switch (fiber.tag) {
    case FunctionComponent: {
      1. 发现 (<div/> fiber).deletions 数组不为空,遍历 deletions,
      把对应的 dom 节点卸载掉(往上找到最近的dom,调用
      dom.removeChild()卸载)
      2.先对子 <Daughter /> Fiber 执行 commitMutationEffectsOnFiber,
      // recursivelyTraverseMutationEffects()
        
      3.递归完,才处理 <div /> Fiber 自己,这里暂时没做什么
      // commitReconciliationEffects() 
    }
  }
}

🔥【图解 React】🚀Vue 转 React 必备🚀(二)React 18 重渲染市面上的某些源码解析,没有一个 🔥【图解 React】🚀Vue 转 React 必备🚀(二)React 18 重渲染市面上的某些源码解析,没有一个

  • <Daughter /> Fiber 执行 commitMutationEffectsOnFiber
  • 引用 Placement 副作用,连接父子 dom 节点
function commitMutationEffectsOnFiber() {
  switch (fiber.tag) {
    case FunctionComponent: {
      1.递归函数: 里面先对子 <div /> Fiber 执行 commitMutationEffectsOnFiber
      // recursivelyTraverseMutationEffects()
      
      2.递归完,才处理 <Daughter /> Fiber 自己
        2.1 发现 <Daughter /> Fiber 有一个 Placement 的副作用
        2.2 应用副作用,fiber 树往上遍历找到最近的父 dom 节点,fiber 树往下遍历找到最近的
        子 dom 节点,插入进去
      // commitReconciliationEffects() 
    }
  }
}

🔥【图解 React】🚀Vue 转 React 必备🚀(二)React 18 重渲染市面上的某些源码解析,没有一个 🔥【图解 React】🚀Vue 转 React 必备🚀(二)React 18 重渲染市面上的某些源码解析,没有一个

  • <div /> Fiber 执行 commitMutationEffectsOnFiber,没做啥省略

版权归许泽川所有

如需转载,请提前询问本人的许可

转载自:https://juejin.cn/post/7412504006340853800
评论
请登录