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旧的备用节点。

相关推荐
MiyueFE14 分钟前
bpmn-js 源码篇7:Featrues 体验优化与功能扩展(二)
前端
好_快28 分钟前
Lodash源码阅读-isPrototype
前端·javascript·源码阅读
315356691343 分钟前
manus邀请码申请手把手教程
前端·后端·面试
烂蜻蜓2 小时前
HTML 编辑器推荐与 VS Code 使用教程
前端·python·编辑器·html
小画家~2 小时前
第五十九:子传父 defineEmits
前端·javascript·vue.js
html组态2 小时前
组态软件在物联网中的应用概述
前端·物联网·编辑器·html·iot
咖啡虫2 小时前
react中的useContext-弊端(二)
前端·javascript·react.js
懒人村杂货铺2 小时前
react精简面试题
前端·react.js·前端框架
青红光硫化黑2 小时前
React基础之tsx语法
前端·javascript·react.js
好_快2 小时前
Lodash源码阅读-isEmpty
前端·javascript·源码阅读