react 类组件生命周期

简介


类组件生命周期

React 生命周期的主要作用是管理组件在不同阶段的行为。它允许开发者在组件的生命周期钩子函数中执行特定的操作,从而控制组件的行为、状态和渲染。

生命周期流程图

constructor

js 复制代码
const instance = workInProgress.stateNode;
if(instance === null){
    // new Component(nextProps, context)
    constructClassInstance(workInProgress, Component, nextProps);
}

实例化只会一次,所以后面都会使用这一个实例类;执行时机在beginWork阶段,也是别人常说的reconciler阶段。

getDerivedStateFromProps(nextProps, prevState)

js 复制代码
let partialState = getDerivedStateFromProps(nextProps, prevState);
const memoizedState =
  partialState === null || partialState === undefined
    ? prevState
    : assign({}, prevState, partialState);
// this.state === memoizedState;

后面获取的state就是getDerivedStateFromProps合并之后的state值,这是一个同步方法,异步不会更新。执行时机在beginWork阶段。

componentDidMount()

js 复制代码
// commitRoot阶段
if (current === null) {
    instance.componentDidMount();
}

在beginWork中判断是否有componentDidMount方法,如果有workInProgress.flag |= Update标记(这个就是react目前不立即执行,有一些生命周期或者副作用等方法在后面特定的时间执行),这个执行的时机和useLayoutEffect是一样的。

shouldComponentUpdate(newProps,newState,context)

js 复制代码
if (instance === null) {
} else if (current === null) { }
else {
    // 更新阶段
    // getDerivedStateFromProps 执行
    shouldUpdate = shouldComponentUpdate(newProps,newState,context)
}

执行时机在beginWork阶段,在getDerivedStateFromProps后面会立即执行shouldComponentUpdate方法,是一个同步方法。

render()

js 复制代码
let shouldUpdate
if (instance === null) {
    // mount 阶段
    shouldUpdate = true;
} else if (current === null) { }
else {
    // 更新阶段
    shouldUpdate = shouldComponentUpdate(newProps,newState,context)
}
// didCaptureError判断是否是异常
if (!shouldUpdate && !didCaptureError) {
    return
}
nextChildren = instance.render()

在没有异常且shouldUpdate=true的情况下更新,在beginWork阶段。

getSnapshotBeforeUpdate(prevProps, prevState);

js 复制代码
// beginWork阶段
workInProgress.flags |= Snapshot;

// 执行 getSnapshotBeforeUpdate 的时机
commitBeforeMutationEffects(
  root,
  finishedWork,
)

// 真实dom挂载
commitMutationEffects(root, finishedWork, lanes);

commitBeforeMutationEffects 的代码逻辑

js 复制代码
if((flags & Snapshot) !== NoFlags){
    if(current !== null){
        const snapshot =  instance.getSnapshotBeforeUpdate(
          prevProps,
          prevState,
        );
        instance.__reactInternalSnapshotBeforeUpdate = snapshot;
    }
}

getSnapshotBeforeUpdate是在真实dom之前执行的,这个也是唯一个在virtual dom创建完成之后,真实dom更新之前执行的,并将结果保存,执行阶段是在更新阶段才会执行。同步执行

componentDidUpdate(prevProps,prevState,__reactInternalSnapshotBeforeUpdate)

js 复制代码
// commitRoot阶段 
if (current === null) { 
    instance.componentDidMount(); 
}else{
    instance.componentDidUpdate(
      prevProps,
      prevState,
      instance.__reactInternalSnapshotBeforeUpdate,
    );
}

componentDidMount和componentDidUpdate是同一阶段执行的,didMount只在首次执行,didUpdate在更新执行,而且didUpdate也是有参数的。

componentWillUnmount()

js 复制代码
// commitMutationEffects
instance.componentWillUnmount();

在真实dom挂载之前,是先判断是否是删除的,如果是删除的状态会执行componentWillUnmount方法。

fiber 遍历顺序

react的fiber是深度遍历,遍历顺序如图所示。

所有生命周期执行顺序

首先执行workLoop 函数,遍历fiber树,这个函数有有两个作用,beginWork 向下执行,completeUnitOfWork 向上执行。

commitRoot阶段,执行先判断是否特定的flags,如果有就执行scheduleCallback 方法的回调,flushPassiveEffects,这是一个react的任务队列,可以理解成下一个宏任务;执行commitBeforeMutationEffects 方法,会遍历fiber树,执行特定的方法,然后执行commitMutationEffects方法,继续遍历fiber树,执行commitMutationEffects方法,再执行commitLayoutEffects方法。

每个矩形都可能遍历一次fiber树,然后执行特定功能,会执行相关生命周期。

问题

为什么要删除 componentWillMount, componentWillUpdate, componentWillReceiveProps生命周期?

  1. 执行时机,渲染过程中可能被中断,导致多次执行;
  2. 渲染时机,此时最新的dom还没准备好,可能导致渲染问题;
  3. 多次渲染,滥用setState会导致多次重复渲染;

static getDerivedStateFromProps 方法替代可以看出,已经禁止使用通过setState来改变state值。

生命周期触发是同步还是异步的?

同步的,React 会立即执行该方法中的代码,而不会等待其他任务完成。

为什么要废弃componentWillReceiveProps改用static getDeriveStateFromProps?

  1. 执行时机不确定,只有props或者context有变化的时候才会执行,而getDeriveStateFromProps函数执行就会执行该方法。
  2. 更改state只能通过setState才会改变,而改变最新的state之后在下次更新的时候获取,会多一次更新,getDeriveStateFromProps通过state和props同步更新最新的state,直接返回。
  3. 因为多一次更新,也会影响到其他的生命周期的执行。
相关推荐
老坛00115 分钟前
2025决策延迟的椭圆算子分析:锐减协同工具的谱间隙优化
前端
老坛00116 分钟前
从记录到预测:2025新一代预算工具如何通过AI实现前瞻性资金管理
前端
今禾19 分钟前
" 当Base64遇上Blob,图像转换不再神秘,让你的网页瞬间变身魔法画布! "
前端·数据可视化
华科云商xiao徐23 分钟前
高性能小型爬虫语言与代码示例
前端·爬虫
十盒半价24 分钟前
深入理解 React useEffect:从基础到实战的全攻略
前端·react.js·trae
攀登的牵牛花25 分钟前
Electron+Vue+Python全栈项目打包实战指南
前端·electron·全栈
iccb101325 分钟前
我是如何实现在线客服系统的极致稳定性与安全性的
前端·javascript·后端
一大树26 分钟前
Vue3祖孙组件通信方法总结
前端·vue.js
不要进入那温驯的良夜27 分钟前
跨平台UI自动化-Appium
前端
海底火旺28 分钟前
以一个简单的React应用理解数据绑定的重要性
前端·css·react.js