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. 因为多一次更新,也会影响到其他的生命周期的执行。
相关推荐
热爱编程的小曾20 分钟前
sqli-labs靶场 less 8
前端·数据库·less
gongzemin31 分钟前
React 和 Vue3 在事件传递的区别
前端·vue.js·react.js
Apifox44 分钟前
如何在 Apifox 中通过 Runner 运行包含云端数据库连接配置的测试场景
前端·后端·ci/cd
树上有只程序猿1 小时前
后端思维之高并发处理方案
前端
庸俗今天不摸鱼2 小时前
【万字总结】前端全方位性能优化指南(十)——自适应优化系统、遗传算法调参、Service Worker智能降级方案
前端·性能优化·webassembly
黄毛火烧雪下2 小时前
React Context API 用于在组件树中共享全局状态
前端·javascript·react.js
Apifox2 小时前
如何在 Apifox 中通过 CLI 运行包含云端数据库连接配置的测试场景
前端·后端·程序员
一张假钞2 小时前
Firefox默认在新标签页打开收藏栏链接
前端·firefox
高达可以过山车不行2 小时前
Firefox账号同步书签不一致(火狐浏览器书签同步不一致)
前端·firefox
m0_593758102 小时前
firefox 136.0.4版本离线安装MarkDown插件
前端·firefox