React深入了解原理

 更新时间:2022年07月29日 15:39:58   作者:_语墨  
React是用于构建用户界面的JavaScript库, [1]  起源于Facebook的内部项目,该公司对市场上所有 JavaScript MVC框架都不满意,决定自行开发一套,用于架设Instagram的网站

VDOM(虚拟dom)

react和vue都是基于vdom的前端框架。

web界面由DOM树来构建,当其中一部分发生变化时,其实就是对应的某个节点发生了变化。

若一次操作中有十次更新DOM的动作,虚拟DOM不会立即操作DOM,而是将这十次更新的diff内容保存到本地的一个js对象中,最终将这个js对象一次性attach到DOM树上,再进行后续的操作。

用js对象模拟DOM节点的好处是:

  • 页面的更新可以先全部反映在js对象(虚拟DOM)上,精准的对比关心的属性,避免大量无谓的计算。等更新完成后,再将最终的js对象映射成真是的DOM,交由浏览器去绘制。
  • 为应用带来的跨平台的能力,不再仅仅局限于浏览器端。比如:React-Native、canvas等。
//虚拟dom对象
{
    type: 'div',
    props: {
        id: 'aaa',
        className: ['bbb', 'ccc'],
        onClick: function() {}
    },
    children: []
}

react中,jsx由babel转义再经过render后生成我们想要的VDOM(虚拟DOM)。

Fiber架构

react15的时候,和 vue 的渲染流程还是很像的,都是递归渲染 vdom,增删改 dom 就行。

但是因为状态管理的差异导致了架构的差异。react的setState会渲染整个vdom,而一个应用的所有 vdom 可能是很庞大的,计算量就可能很大。

浏览器里 js 计算时间太长是会阻塞渲染的,会占用每一帧的动画、重绘重排的时间,这样动画就会卡顿。

那能不能把计算量拆分一下,每一帧计算一部分,不要阻塞动画的渲染呢?

顺着这个思路,react 就改造为了 fiber 架构,目标是打断计算,分多次进行。

渲染的时候不要直接更新到 dom 了,只找到变化的部分,打个增删改的标记,创建好 dom,等全部计算完了一次性更新到 dom 就好了。

初始化渲染

根据 React Element 生成对应的 Fiber 树

1.根据 React Element 生成对应的 Fiber 树

首次执行ReactDOM.render 会创建fiberRoot 和 rootFiber。

  1. fiberRoot:整个应用的根节点(只能有一个)
  2. rootFiber:组件树的根节点(可以有多个)

2.根据组件返回的JSX在内存中依次创建Fiber节点,并连接在一起构建形成Fiber树,被称为workInProgress Fiber树。最后以 workInProgress 作为最新的渲染树,fiberRoot 的 current 指针指向 workInProgress 使其变为 current Fiber 树。到此完成初始化流程。

  1. workInProgress:正在内存中构建的 Fiber 树称为 workInProgress Fiber树。在一次更新中,所有的更新都是发生在 workInProgress 树上。在一次更新之后,workInProgress 树上的状态是最新的状态,那么它将变成 current 树用于渲染视图。
  2. current:正在视图层渲染的树叫做 current 树。

更新时

render阶段,创建 dom,打上增删改的 tag,等全部计算完之后,commit 阶段一次性更新到 dom。

render阶段

beginWork和completeWork阶段会循环最新的jsx生成的虚拟dom,通过对比虚拟dom和current Fiber树生成workinProgress Fiber树。

beginWork

创建本次循环主体的子Fiber节点

  • mount(首屏渲染)时创建子Fiber节点,并返回改新建节点;
  • update时若不满足复用条件,则与mount时一样创建新的子fiber节点,并diff出相应的effTag挂在FIber节点上,并返回该新建节点;
  • updata时若满足复用条件,且判断仍需处理其子节点的后代,则返回复用后的子Fiber节点
  • updata时若满足复用条件,且判断不需继续处理其子节点的后代,则直接返回null值;

completeWork

构建或更新DOM节点

  • 构建过程中,会自下而上将子节点插入到当前节点
  • 更新过程中,会计算DOM 节点的属性,一旦属性需要更新,会为DOM节点对应的workINProgress节点标记Update的effectTag

自下而上收集effectList,最终收集到root上

Diff到底是谁跟谁比?

Diff 是 vdom 和 current Fiber 对比,生成 workInProgressFiber

effectTag与effectList

render阶段不会真正操作dom,只会创建dom然后打个effectTag的增删改标记。commit阶段就根据标记来更新dom就可以了。

但是commit阶段要在遍历一次fiber来查找有effectTag的节点,更新dom吗?

当然没问题,但是显然很低效。完全可以把有 effectTag 的节点收集到一个链表里,然后 commit 阶段直接遍历这个链表就行了。这个链表叫做 effectList。

react 会在 commit 阶段遍历 effectList,根据 effectTag 来增删改 dom。

这个队列叫做 effectList。

commit阶段

render阶段找到变化的部分,创建dom,打上增删改的tag,等全部计算完之后,commit阶段一次性更新到dom。

before mutation阶段(执行DOM操作前)

遍历effectList,依次执行:

1.处理DOM节点渲染/删除后的autoFocus、blur逻辑

2.调用getSnapshotBeforeUpdate生命周期钩子

3.调度useEffect mutation阶段(执行DOM操作)

遍历 effectList 来更新 dom

layout阶段(执行DOM操作后)

因为这个阶段已经可以拿到布局信息了,会同步调用 useLayoutEffect 的回调函数。而且这个阶段可以拿到新的 dom 节点,还会更新下 ref。

到此这篇关于React深入了解原理的文章就介绍到这了,更多相关React原理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 详解使用WebPack搭建React开发环境

    详解使用WebPack搭建React开发环境

    这篇文章主要介绍了详解使用WebPack搭建React开发环境,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-08-08
  • react build 后打包发布总结

    react build 后打包发布总结

    这篇文章主要介绍了react build 后打包发布总结,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-08-08
  • 详解React如何优雅地根据prop更新state值

    详解React如何优雅地根据prop更新state值

    这篇文章主要为大家详细介绍了React如何优雅地实现根据prop更新state值,文中的示例代码讲解详细,具有一定的参考价值,感兴趣的小伙伴可以了解下
    2023-11-11
  • 解决react-connect中使用forwardRef遇到的问题

    解决react-connect中使用forwardRef遇到的问题

    这篇文章主要介绍了解决react-connect中使用forwardRef遇到的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-05-05
  • 深入理解React与闭包的关系

    深入理解React与闭包的关系

    本文将深入探讨React与闭包之间的关系,我们将首先介绍React和闭包的基本概念,然后详细解释React组件中如何使用闭包来处理状态和作用域的问题,希望通过本文的阅读,你将对React中闭包的概念有更深入的理解,并能够在开发React应用时更好地应用闭包
    2023-07-07
  • GraphQL在react中的应用示例详解

    GraphQL在react中的应用示例详解

    这篇文章主要为大家介绍了GraphQL在react中的应用示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-10-10
  • 详解React-Native全球化多语言切换工具库react-native-i18n

    详解React-Native全球化多语言切换工具库react-native-i18n

    这篇文章主要介绍了详解React-Native全球化语言切换工具库react-native-i18n,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-11-11
  • 一文详解React类组件中的refs属性

    一文详解React类组件中的refs属性

    react中的ref类似于vue中的ref,都是可以操作dom的,这篇文章我们通过一个demo来学习这个属性,文中有详细的代码示例供大家参考,具有一定的参考价值,需要的朋友可以参考下
    2023-08-08
  • ReactJs实现树形结构的数据显示的组件的示例

    ReactJs实现树形结构的数据显示的组件的示例

    本篇文章主要介绍了ReactJs实现树形结构的数据显示的组件的示例,非常具有实用价值,需要的朋友可以参考下
    2017-08-08
  • React ant 点击导航条闪烁问题解决

    React ant 点击导航条闪烁问题解决

    很多小伙伴反馈React ant 点击导航条闪烁,没有传递具体的参数给点击事件 , 导致在函数内部无法准确判断要展示哪个子菜单,可能导致页面状态的短暂变化,出现闪烁效果,下面给大家分享解决方法,感兴趣的的朋友跟随小编一起看看吧
    2024-04-04

最新评论