React双缓存树渲染流程介绍

一、什么是React Fiber

我们都知道从React16.8开始引入了fiber架构。旧版的React的render过程是同步的,如果Render耗时较长,会阻塞页面的其他任务。新版本的Render过程拆分成多个异步任务(纤程),并且是可中断可恢复的,这就是React Fiber.

原理:Render过程主要工作是vdom diff算法找出两棵树的区别,本质上的树的遍历。在旧版本react,假设遍历发生了中断,虽然可以保留当下进行中节点的索引,下次继续时,我们的确可以继续遍历该节点下面的所有子节点,但是没有办法找到其父节点因为每个节点只有其子节点的指向。断点没有办法恢复,只能从头再来一遍。在新的fiber架构中,每个节点有三个指针:分别指向第一个子节点、下一个兄弟节点、父节点。这种数据结构就是fiberNode。

二、React双缓冲树

javascript 复制代码
import React from 'react';
import ReactDom from 'react-dom';

class Home extends React.Component {
  constructor(props) {
     super(props);
     this.state = { step: 0 };
     this.handleClick = this.handleClick.bind(this);
   }
   handleClick() {
     this.setState({step: this.state.step + 1})
    }
  render() {
     const { step } = this.state;
     return (
         <div id={step} onClick={this.handleClick}>
            {step}
         </div>
       )
     }
  }

ReactDom.render(<Home/>, document.getElementById('root'))

渲染流程

  • render阶段 构建workInProgress树,用于本次渲染
  • render结束,commit前 更新容器的finishedWork指针,通知页面渲染
  • commit结束 current树变成alternate树,workInProgress树变成current树,finishedWork树为空

第一次渲染

  • render阶段 初始化工作:创建容器和root fiberNode, current指针指向root fiber
  • 构建workInProgressi树,即将渲染到页面的vdom 除了child、sibling、return:指针,还有alternate它指向备用节点
  • render阶段结束,commit阶段开始 将fiber树容器的finishedWork指针执行workInProgress树root节点
  • commit阶段结束 current指向workInProgree树,finishedWork指向null

第二次渲染

  • render阶段 在current树的基础上构建workInProgress树,current.alternate节点不为空,存在备用节点,直接复用。

current树的其他子节点的alternate都为null,各自创建workInProgress节点

  • render阶段结束,commit阶段开始

    将fiber树容器的finishedWork指针指向workInProgress树root节点

  • commit阶段结束

    current指向workInProgress树,finishedWork指向null

第三次渲染

  • render阶段

    构建workInProgress树,所有fiber节点存在备用节点,直接复用,并将属性复制过去。

  • render阶段结束,commit阶段开始 将fiber树容器的finishedWork指针执行workInProgress树root节点
  • commit阶段结束

    current指向workInProgress树,finishedWork指向null

三、结论

通过上面三次渲染更新过程也可以看出,React在渲染时,会在current树和alternate树之间交替进行,倒来倒去。比如第四次渲染时,第二次渲染完成的alternate树又变成了current树,而第三次渲染完成的树又变成了alternate树。 那为什么React要复用备用的节点,而不是新创建一个呢?最大的原因是节省内存开销,通过复用引旧的备用节点,React不需要额外申请内存空间,在复用时可以直接将current fiber的属性复制到l旧的备用节点。

相关推荐
0和1的舞者3 小时前
Spring AOP详解(一)
java·开发语言·前端·spring·aop·面向切面
web小白成长日记3 小时前
在Vue样式中使用JavaScript 变量(CSS 变量注入)
前端·javascript·css·vue.js
QT 小鲜肉3 小时前
【Linux命令大全】001.文件管理之which命令(实操篇)
linux·运维·服务器·前端·chrome·笔记
C_心欲无痕3 小时前
react - useImperativeHandle让子组件“暴露方法”给父组件调用
前端·javascript·react.js
BullSmall5 小时前
支持离线配置修改及删除操作的实现方案
前端
全栈前端老曹6 小时前
【前端路由】Vue Router 嵌套路由 - 配置父子级路由、命名视图、动态路径匹配
前端·javascript·vue.js·node.js·ecmascript·vue-router·前端路由
EndingCoder6 小时前
安装和设置 TypeScript 开发环境
前端·javascript·typescript
张雨zy6 小时前
Vue 项目管理数据时,Cookie、Pinia 和 LocalStorage 三种常见的工具的选择
前端·javascript·vue.js
五月君_7 小时前
Nuxt UI v4.3 发布:原生 AI 富文本编辑器来了,Vue 生态又添一员猛将!
前端·javascript·vue.js·人工智能·ui
!执行7 小时前
遇到 Git 提示大文件无法上传确实让人头疼
前端·github