React 生命周期

react

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 安装
// 当组件的实例被创建并插入到 DOM 中时,这些方法按以下顺序调用:

constructor()
static getDerivedStateFromProps()
render()
componentDidMount()

// 更新中
// 更新可能由道具或状态的更改引起。当重新渲染组件时,这些方法按以下顺序调用:

static getDerivedStateFromProps()
shouldComponentUpdate()
render()
getSnapshotBeforeUpdate()
componentDidUpdate()

// 卸载
// 当组件从 DOM 中移除时调用此方法:

componentWillUnmount()
react-fiber

背景

react-fiber 产生的根本原因,是大量的同步计算任务阻塞了浏览器的 UI 渲染。默认情况下,JS 运算、页面布局和页面绘制都是运行在浏览器的主线程当中,他们之间是互斥的关系。如果 JS 运算持续占用主线程,页面就没法得到及时的更新。当我们调用setState更新页面的时候,React 会遍历应用的所有节点,计算出差异,然后再更新 UI。如果页面元素很多,整个过程占用的时机就可能超过 16 毫秒,就容易出现掉帧的现象。

实现原理

  • react 内部运转分三层:

    • Virtual DOM 层,描述页面长什么样。
    • Reconciler 层,负责调用组件生命周期方法,进行 Diff 运算等。
    • Renderer 层,根据不同的平台,渲染出相应的页面,比较常见的是 ReactDOM 和 ReactNative。

Fiber 其实指的是一种数据结构,它可以用一个纯 JS 对象来表示 :

1
2
3
4
5
6
const fiber = {
stateNode, // 节点实例
child, // 子节点
sibling, // 兄弟节点
return, // 父节点
}
  • 为了实现不卡顿,就需要有一个调度器 (Scheduler) 来进行任务分配。优先级高的任务(如键盘输入)可以打断优先级低的任务(如 Diff)的执行,从而更快的生效。任务的优先级有六种:

    • synchronous,与之前的 Stack Reconciler 操作一样,同步执行
    • task,在 next tick 之前执行
    • animation,下一帧之前执行
    • high,在不久的将来立即执行
    • low,稍微延迟执行也没关系
    • offscreen,下一次 render 时或 scroll 时才执行
  • Fiber Reconciler(react )执行过程分为 2 个阶段:

    • 阶段一,生成 Fiber 树,得出需要更新的节点信息。这一步是一个渐进的过程,可以被打断。阶段一可被打断的特性,让优先级更高的任务先执行,从框架层面大大降低了页面掉帧的概率。
    • 阶段二,将需要更新的节点一次过批量更新,这个过程不能被打断。
  • Fiber 树:React 在 render 第一次渲染时,会通过 React.createElement 创建一颗 Element 树,可以称之为 Virtual DOM Tree,由于要记录上下文信息,加入了 Fiber,每一个 Element 会对应一个 Fiber Node,将 Fiber Node 链接起来的结构成为 Fiber Tree。Fiber Tree 一个重要的特点是链表结构,将递归遍历编程循环遍历,然后配合 requestIdleCallback API, 实现任务拆分、中断与恢复。

从 Stack Reconciler 到 Fiber Reconciler,源码层面其实就是干了一件递归改循环的事情