首页 > 其他分享 >React Diff

React Diff

时间:2024-08-13 22:18:55浏览次数:8  
标签:oldFiber current fiber React 遍历 newChildren Diff 节点

React Diff流程

前提

在React的render阶段的beginWorl方法中对于update的组件会通过reconcileChildFibers方法将当前组件与该组件在上次更新时对应的Fiber节点进行比较(即diff算法),将比较的结果生成新的Fiber节点,即创建workInProgress fiber的过程。
其中,在某一时刻,一个DOM节点最多会存在4个节点与它相关:

  • current fiber,页面中正在显示的DOM对应的Fiber节点
  • workInProgress fiber,内存中正在构建的Fiber节点
  • DOM节点本身
  • JSX对象,ClassComponent或者FunctionComponent的返回值

diff算法的本质就是对比current fiber和JSX对象,然后生成workInProgress fiber。

DIff的瓶颈

因为diff操作本身会带来性能损耗,即算法复杂度过高,所以React的应对方法是预设三个限制:

  • 只对同级元素进行diff
  • 两个不同类型的元素会产出不同的fiber树
  • 设置key属性

Diff的实现

reconcileChildFibers方法中对同级的节点针对节点的数量会分为两类进行处理:单节点的DIff和多节点的Diff。

单节点的Diff

首先React会判断前后元素的key的值是否相等,如果相等则会继续比较type的值是否相等,如果都相等则表示可以复用current fiber节点部分属性来创建workInProgress fiber节点。

如果前后元素的key相等,但是type的值不相等,那么会将current fiber以及它的兄弟fiber节点都标记为删除。

如果前后元素的key不相等,那么将current fiber节点标记删除。

然后接着移动sibling指针继续比较current fiber的兄弟fiber节点与当前元素进行比较,重复上述的过程。

多节点的diff

多节点的diff会经历两轮遍历:

  • 第一轮遍历处理更新的节点
  • 第二轮遍历处理剩下不属于更新的节点

第一轮遍历

主要流程还是会通过遍历current fiber和当前同级元素进行key和type的比较。

  • 如果key和type都相同,则会复用current fiber节点来创建workInProgress fiber节点
  • 如果key相同,但type不同,则会重新创建workInProgress fiber节点
  • 如果key不同,则直接退出第一轮遍历

如果newChildren遍历完,也会退出第一轮遍历。

第二轮遍历

在经过第一轮遍历之后会出现四种情况:

  • 情况一:newChildren 和 oldFiber 同时遍历完了
  • 情况二:newChildren 没有遍历完,oldFiber 遍历完了
  • 情况三:newChildren 遍历完了,oldFiber 没有遍历完了
  • 情况四:newChildren 和 oldFiber 都没有遍历完

针对情况 1 和 情况 3 oldFiber 遍历完的情况,将剩余的 newChildren 标记为插入。
针对情况 2 newChildren 遍历完的情况,将剩下的 oldFiber 标记为删除。

针对最为复杂的情况 4 要做的是处理移动的节点。而对于移动的节点可能进行的操作是新增和删除。
哪如果判断一个节点在更新前后是否发生了移动呢?找到一个参照物,然后比较当前元素和该参照物在更新前后的相对位置是否发生了变化。
为此 React 定义了两个关键变量 oldIndex 和 lastPlacedIndex。

  • oldIndex 表示通过遍历 newChildren 拿到的该元素对应 oldFiber 中该节点的 index
  • lastPlacedIndex 表示 oldFiber 当中最后一个可复用元素的 index

这个根据 newChildren 遍历到的元素查找对应 oldFiber 的过程是:先将剩余的 oldFiber 都保存在变量名为为 existingChildren 的 map 数据结构。oldFiber 的 key 为 key,oldFiber 为 value。
然后通过遍历到的 newChildren 元素的 key 属性找到对应的 oldFiber 节点,再根据两者的 type 是否相同决定是否复用该 oldFiber。如果相同则复用 current fiber 创建 workInProgress fiber 节点。如果不相同则重新创建 workInProgress fiber 节点,然后标记为插入。

lastPlacedIndex 的初始值为 0。通过比较 oldIndex 和 lastPlacedIndex 的大小就能判断当前元素的位置是否发生了移动。
如果 oldIndex >= lastPlacedIndex,表示当前元素和参照物的相对位置没有发生变化, 所以可以复用该元素对应的 current fiber 节点来创建 workInProgress fiber。然后将 oldIndex 赋值给 lastPlacedIndex,继续遍历下一个元素。
而如果 oldIndex < lastPlacedIndex,则表示当前元素和参照物的相对位置发生了变化,则将该元素的 current fiber 标记为删除,然后重新创建 workInProgress fiber 并标记插入。

(举例:oldFiber 中有两个节点:fiber 1 和 fiber 2。newChildren 有两个元素:element 2 和 element 1。 因为 newChildren 的遍历顺序是从前往后的,也就是说会先遍历element 1,再遍历element 2。element 2 对应 oldFiber 中 fiber 2 的 index 为 1,可以复用 fiber 2节点。然后赋值 lastPlacedIndex = oldIndex = 1。继续遍历 element 1,element 1 对应的 oldFibr 中 fiber 1 的 index 为 0,oldIndex < lastPlacedIndex,说明 element 1 在更新前后的位置发生了变化,所以将 fiber 1 标记删除,根据 element 1 重新创建的 workInProgress fiber 标记为插入)

直到遍历完 newChildren,再遍历 existingChildren 将剩下的 oldFiber 都标记为删除。

结束 diff 算法。

标签:oldFiber,current,fiber,React,遍历,newChildren,Diff,节点
From: https://www.cnblogs.com/rocenjs/p/18357605

相关文章

  • 题解:CF1971B Different String
    原地址:这里题意给出字符串\(s\),询问更改\(s\)的排列顺序后与原来的\(s\)是否不同,不同输出YES,否则输出NO。思路只要判断字符串中含有不同的字符即可。代码#include<iostream>#include<cstdio>usingnamespacestd;intmain(){ intt; scanf("%d",&t); while(t-......
  • Stable Diffusion教程|SD WebUI必备插件安装 菜鸟轻松成高手
    一个刚学AI绘画的小菜鸟怎么快速成为StableDiffusionde的高手?答案就是SD插件,只要学会使用SD的各种插件,帮你写正向和负向提示词,修复人脸/身体/手指,高清放大图片,指定人物pose,图片微调等等都可以轻松搞定,善用插件是成为高手必经之路。目录1插件安装方法2基础插件介绍3......
  • Stable Diffusion 4.8.7升级版更新,Ai绘画风口已来!(无需部署,解压即用)
    2024可以称得上是Ai技术大爆发的元年,目前两款Ai神器大火,一款是大名鼎鼎的ChatGPT。另外一款大火的是本期介绍的Ai绘图软件—StableDiffusion。5月**StableDiffusionAi绘画最新版本更新啦!此次从4.7更新至4.8.7版本!**主要是更新优化和大模型增加,无需复杂的部署,解压即用......
  • 使用Vite+TS+Antd构建React项目
    安装Vitenpminstall-gvite#yarnglobaladdvite创建React项目vitecreatemy-react-app--templatereact-ts安装ReactRouternpminstallreact-router-dom@types/react-router-dom#yarnaddreact-router-dom@types/react-router-dom安装AntDesign......
  • AI绘画实操 Stable Diffusion 到底怎么玩儿,新手必看的AI绘画入门安装使用教程
    大家好,我是灵魂画师向阳2024年,是AI绘画技术飞速发展的一年,各种AI绘画工具层出不穷,为了让大家在了解和学习AI绘画的过程中少走弯路,今天我将详细介绍目前世界上使用用户最多,社区最大,生态最丰富的免费图像生成模型——StableDiffusion,并为你提供详细的安装教程,让你轻松踏入AI......
  • react-navigation使用redux-saga等处理各种跳转、清除堆栈、返回不同页面的问题
    react-navigation使用redux-saga等处理各种跳转、清除堆栈、返回不同页面的问题名字还是土一点好关注IP属地:上海0.272018.01.2114:26:36字数154阅读4,027一直没有找到有关于 react-navigation 处理app各种不同状态需要默认不同首页的例子,于是只能自己写了。整个......
  • React Router v6 使用指南
    ReactRouterv6使用指南杭州程序员张张 2020-08-19阅读 7 分钟19 本文首发于公众号《前端全栈开发者》,第一时间阅读最新文章,会优先两天发表新文章。关注后私信回复:大礼包,送某网精品视频课程网盘资料,准能为你节省不少钱!在本教程中,让我们看一下......
  • React Router 6 (React路由) 最详细教程
    ReactRouter6(React路由)最详细教程蒋川 2022-03-29阅读 5 分钟3 ReactRouter 经历多个版本的发展,现在已经到了 ReactRouter6。虽然网络上写React-Router路由本身的教程很多,但真正讲到React-Router6的并不多。同时因为第6版引......
  • 07-react应用-组件化编码
    目录样式模块化功能界面的组件化编码流程(通用)案例总结todoList案例相关知识点样式模块化//样式模块化index.module.cssimporthellofrom'./index.module.css'divclassName={hello.title}功能界面的组件化编码流程(通用)拆分组件:拆分界面,抽取组件实......
  • 使用 Python 操作 Stable Diffusion 进行 AI 绘图
    在几年前,AI领域对于普通人来说,还是无法触及的高岭之花。但随着chatGPT的爆火,AI变得越来越大众化,大量的工具让你可以在不具备任何前置知识的情况下使用AI,其中最火热的便是AI绘图了。相信很多人都知道Midjourney这个网站,只要输入相关的文字,便可通过网站背后的AI产出相对......