【React】再探组件lifeCycle(以RCC为例)

255 阅读4分钟

概念

  • instance : 类组件对应的实例
  • Fiber React 中使用双缓存的机制,来完成 Firber树的构建与替换,实现 Dom 对象的快速更新。
  • React 中会同时存在两个 Fiber 对象,当前在屏幕中显示的树是 CurrentFiber 树,当发生更新时,React会重新创建一颗新的Firber树是 WorkInProgress Firber树。在双缓存技术中,workInProgress Fiber 树就是即将显示在页面中的 Fiber树,当这个Fiber 树构建完成后,React 会将它直接与 Current Firber 树进行替换,进而达到 快速更新 Dom 的操作,因为 workInProgress Fiber 在更新的过程中,是在内存中构建的,所有速度是非常快的,得到最终更新后的 Firber,直接替换 Current Firber。. current Firber 树有一个 alternate 属性指向 workInProgress Firber 树,workInProgress Firber 树内也 有一个alternate 属性指向current Firber 树
  • workInProgress 树,当前正在调和的 fiber 树 ,一次更新中,React 会自上而下深度遍历子代 fiber ,如果遍历到一个 fiber ,会把当前 fiber 指向 workInProgress。
  • current 树,在初始化更新中,current = null ,在第一次 fiber 调和之后,会将 workInProgress 树赋值给 current 树。React 来用workInProgress 和 current 来确保一次更新中,快速构建,并且状态不丢失。
  • renderExpirationTime 作为下一次渲染的过期时间。

React生命周期

image.png

由上图可以看到,整个生命周期可以分为Render阶段和commit阶段,对于类组件来说,大部分生命周期的执行进行在mountClassInstanceupdateClassInstance中。

render阶段

构造函数执行(constructor)

组件实例挂载阶段,constructor执行,首先执行constructClassInstance

  • 首先获取实例的静态方法
  • 执行getDerivedStateFromProps生命周期,得到合并的state

getDerivedFromProps执行

直接从类上绑定静态法昂发,传入props\state,返回后鱼之前的state合并,并作为新的state,传递给组件使用

componentWillMount执行

如果存在getDerivedFromProps和 getSnapshotBeforeUpdate 就不会执行生命周期componentWillMount

render执行

此时mountClassInstance执行结束,updateClassComponent函数执行render,形成chiildren,接下来 React 调用 reconcileChildren 方法深度调和 children 。

commit阶段

componentDidMount执行

一旦调和完所有的fiber结点,就会来到commit阶段在组件初始化 commit 阶段,会调用 componentDidMount 生命周期。

image.png

各阶段生命周期的作用

constructor

初始化工作

  • 初始化state,截取路由中的参数,赋值给state
  • 对组件事件进行处理(绑定this指向,预处理:防抖、节流)
  • 对类组件进行渲染劫持、预处理,如HOC

getDerivedFromProps

意为从参数中拿到派生的state,同时只要组件更新就会执行这个生命周期钩子

  • 代替 componentWillMount 和 componentWillReceiveProps
  • 组件初始化或者更新时,将 props 映射到 state。
  • 返回值与 state 合并完,可以作为 shouldComponentUpdate 第二个参数 newState ,可以判断是否渲染组件。(请不要把 getDerivedStateFromProps 和 shouldComponentUpdate 强行关联到一起,两者没有必然联系)

componentWillReceiveProps

  • componentWillReceiveProps 可以用来监听父组件是否执行 render 。
  • componentWillReceiveProps 可以用来接受 props 改变,组件可以根据props改变,来决定是否更新 state ,因为可以访问到 this , 所以可以在异步成功回调(接口请求数据)改变 state 。这个是 getDerivedStateFromProps 不能实现的。

componentWillUpdate

  • 获取组件更新之前的状态。比如 DOM 元素位置等。

getSnapshotBeforeUpdate

  • getSnapshotBeforeUpdate 这个生命周期意义就是配合componentDidUpdate 一起使用,计算形成一个 snapShot 传递给 componentDidUpdate 。保存一次更新前的信息。

omponentDidUpdate

  • componentDidUpdate 生命周期执行,此时 DOM 已经更新,可以直接获取 DOM 最新状态。这个函数里面如果想要使用 setState ,一定要加以限制,否则会引起无限循环。
  • 接受 getSnapshotBeforeUpdate 保存的快照信息。

componentDidMount

  • 可以做一些关于 DOM 操作,比如基于 DOM 的事件监听器。
  • 对于初始化向服务器请求数据

shouldComponentUpdate

  • 一般用于性能优化,shouldComponentUpdate 返回值决定是否重新渲染的类组件。需要重点关注的是第二个参数 newState ,如果有 getDerivedStateFromProps 生命周期 ,它的返回值将合并到 newState ,供 shouldComponentUpdate 使用。

componentWillUnmount

  • 清除延时器,定时器。
  • 一些基于 DOM 的操作,比如事件监听器。

RFC模拟RCC生命周期(只有不常用的)

useEffect与useLayoutEffect的区别

  • 首先 useLayoutEffect 是在 DOM 更新之后,浏览器绘制之前,这样可以方便修改 DOM,获取 DOM 信息,这样浏览器只会绘制一次,如果修改 DOM 布局放在 useEffect ,那 useEffect 执行是在浏览器绘制视图之后,接下来又改 DOM ,就可能会导致浏览器再次回流和重绘。而且由于两次绘制,视图上可能会造成闪现突兀的效果。
  • useLayoutEffect callback 中代码执行会阻塞浏览器绘制。

useInsertionEffect(React 18)

  • useInsertionEffect 主要是解决 CSS-in-JS 在渲染中注入样式的性能问题。这个 hooks 主要是应用于这个场景,在其他场景下 React 不期望用这个 hooks 。