likes
comments
collection
share

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

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

前言

市面上的某些源码解析,没有一个真实的案例把整个 react 流程串起来。导致看了许多所谓的源码,反而把自己看懵了

所以本系列文章全部从实际案例出发,尽力让零基础未接触 React 的人都能上手源码

本人在未做过 react 项目的前提下先学的源码,所以各位大神应该可以无痛上手

文章中多次提及的 react 源码里面的几个关键函数名,和 fiber 上的一些关键属性名,还有之后可能提及的一些优先级车道相关的东西。

只要了解了,我觉得应该是能够初步具备调试 React 源码的能力的。比如之后可能要写的 React.lazy<Suspense /><OffScreen /> 组件关系的文章,useContext 性能问题文章等,就是我自己调试源码总结出来的。

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

🤖 代码实例

流程图地址 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>
}

🤖 初始化阶段(从这里开始看)

const root = createRoot(document.getElementById('root'))
root.render(<App />)

🚀 createRoot(document.getElementById('root')) 做了什么?

  • 创建 HostRootFiber 这个 fiber 节点

当前 html 文件只有一个 <div id="root" />,所以这个 fiber 节点其实就是第一颗 fiber

  • HostRootFiber fiberDOM(#root) 相关联

🚀 root.render(<App>) 做了什么?

  • 安排一个更新 {element: __jsx(App, {})}

更新内容:根据 App jsx 创建出 App fiber,挂载在 HostRootFiber

  • 触发重渲染,来处理这个更新,生成新的 fiber 树,来替换当前的 fiber

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

howdy ho 🙋‍ im the first fiber tree

🤖 render 阶段

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

创建一个全新的 HostRootFiber,但是复用了旧 HostRootFiber 上的所有属性。双方通过 alternate 互相关联

最后所有工作完成,才去修改current指针到新的 fiber 树完成 fiber 树的切换

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

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

  • HostRootFiber 执行 beginWork,创建出子节点 App Fiber
  • 标记 App FiberflagsPlacement
function BeginWork() {
 switch (fiber.tag) {
   case HostRoot:
     1.上文说到的创建更新,应用更新,将 HostRootFiber.memoizedState = {element: 
     __jsx(App, {})}     
     2.拿到 <App/>的jsx (也就是 HostRootFiber.memoizedState)
     3.当前 fiber 树没有 <App /> Fiber,根据 <App /> jsx 创建新的 <App /> fiber
         
     4.正在构建(workInProgress)的这个 HostRootFiber 的 alternate 不为空(看图:
     当前的页面(current)对应的 fiber 树本来就有一个 HostRootFiber
     4.所以给 <App /> fiber 标记一个插入的副作用,表示等一下要把 <App/> 插入到
     HostRootFiber 下 fiber.flags |= Placement 
         
     5.返回 <App /> fiber 
 }
}

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

App fiber 执行 beginWork,创建出子节点 div Fiber

function BeginWork() {
 switch (fiber.tag) {
  case FunctionComponent: {
    1.拿到函数组件本身(fiber.type)执行,拿到返回的 <div/> jsx 
    2.jsx 跟 当前页面的 Fiber 进行 dom-diff,决定复用或者创建对应的fiber
    3.返回复用或者新创建的 <div/> Fiber
  }
 }
}

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

div Fiber 执行 beginWork,创建出子节点 Son Fiber

function BeginWork() {
 switch (fiber.tag) {
  case HostComponent: { 
    1.拿到 props.children, 也就是 <Son /> jsx 对象
    2.当前 fiber 没有 <Son /> Fiber,根据 <App /> jsx 创建新的 <App /> fiber
    3.返回 <Son /> Fiber
  }
 }
}

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

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

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

Div fiber 执行 completeWork

function completeWork() {
  switch (fiber.tag) {
    case HostComponent: {
      1.通过 document.createElement("div") 【fiber.type】 创建 div dom 节点
      2.fiber 上的 stateNode 属性和 div dom 节点相关联
    }        
  }  
}

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

Son fiber 执行 completeWork,没做啥,省略

Div fiber 执行 completeWork

3. 执行 completeWork
function completeWork() {
  switch (fiber.tag) {
   case HostComponent: {
     1.判断 fiber.stateNode 为空 
     2.通过 document.createElement("div") 创建 div dom 节点   
     3.顺便把所有子 dom 节点挂到自己身上 (dom.appendChild
        // 当页面没有对应dom的时候有一个小优化:这个递归流程,刚好能把子dom都插入到自
        身,之后能省掉这一步操作
        // 当前fiber是新创建的,也就是没有旧fiber,不用担心appendChild到当前页面上真
        实的dom造成页面闪烁,所以能优化
     4.fiber 上的 stateNode 属性和 div dom 节点相关联
   }    
  }  
}

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

App fiber 执行 completeWork,没做啥,省略 对 HostRootFiber fiber 执行 completeWork,没做啥,省略 🔥【图解 React】🚀Vue 转 React 必备🚀(一)React 18 初次渲染市面上的某些源码解析,没有一

🤖 commit 阶段

🚀 递归执行 commitMutationEffectsOnFiber

🚀 应用 fiber 上的副作用 flags,创建真实 dom,或者对 dom 增删查改

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

function schedulerUpdateOnFiber() {

}

版权归许泽川所有

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

TODO 后续文章 1篇/1周

react 重渲染

加餐:重渲染的优先级

加餐:React 重渲染优化,批量更新

加餐:useContext vs 外部数据源

加餐:React 闭包陷阱

加餐:新手误区,何时使用 useState 何时使用 useRef

dom-diff

React.lazy 和 Suspense 原理

加餐:原生 keep-alive 组件 OFFSCREEN

useEffect/useLayoutEffect

REACT 常用工具

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