React 的生命周期 | 青训营

755 阅读4分钟

React 生命周期

首先,拿一个例子来说明React的生命周期流程。

例子:

​ 有一个名为Count的组件,展示当前的总和(初始为0),有一个按钮,每次点击按钮,数字加一,另外还有一个卸载按钮,点击将这个组件在页面中卸载。

代码如下:

class Count extends React.Component {
    constructor(props) {
        console.log("Count组件调用了constructor生命周期钩子");
        super(props);
        this.state = { count: 0 };
    }

    add = () => {
        const { count } = this.state;
        this.setState({ count: count + 1 });
    };
    
    // 组件渲染
    render() {
        console.log("Count组件调用了render生命周期钩子");
        return (
            <div>
                <h1>当前的和为:{this.state.count}</h1>
                <button onClick={this.add}>点我+1</button>
                <button onClick={this.death}>卸载组件</button>
            </div>
        );
    } 
}

展示的效果如下:

效果图.png

旧版本

React中,组件有两种主要的流程,即挂载时更新时

挂载时,一个组件要经历初始化、预挂载、渲染到页面、挂载到页面后,这几个重要的时间点。

对应到代码中:

  1. 初始化:调用类中的构造器函数。
  2. 预挂载:即将把组件展示到页面上,在React中是componentWillMount生命周期钩子。
  3. 渲染到页面:即组件的效果完全展示到页面上的过程,即React组件的render生命周期钩子。
  4. 挂载到页面后:即组件的效果在页面中展示完毕后,在React中是componentDidMount生命周期钩子。

在上面的例子中,我们可以把这些生命周期钩子全部写在组件中,在这些生命周期钩子中我们不做别的事情,仅仅输出一句话,表明调用了该生命周期钩子,按照以上代码已有生命周期钩子中的输出语句写。

最终运行效果:

旧生命周期流程.png

更新时,根据引起更新的原因不同,分为三个更新流程起点。

三种更新的情况:

  1. 父组件引起子组件的更新

    流程:

    componentWillReveiveProps--->shouldComponentUpdate--->componentWillUpdate--->render--->componentDidUpdate

  2. 调用setState引起的更新:

    流程:

    shouldComponentUpdate--->componentWillUpdate--->render--->componentDidUpdate

  3. 调用forceUpdate引起的更新

    流程:

    componentWillUpdate--->render--->componentDidUpdate

componentWillReveiveProps:子组件接收到新的父组件更新的数据,除了第一次

shouldComponentUpdate:组件是否应该更新,这个生命周期钩子像是一个阀门,它返回一个布尔值,true为打开阀门,允许组件更新,false为关闭阀门,不允许组价更新。

componentWillUpdate:组件将要更新,调用forceUpdate方法能够直接从该流程开始,越过了”阀门“,有强制更新组件的意思。

render:将新的组件渲染到页面上的过程。

componentDidUpdate:组件更新完毕后。

用上面同样的方法可以验证组件更新时的生命周期的执行流程。

附上流程图:

react生命周期(旧).png

新版本

React的17版本开始,官方废除了3个生命周期钩子,新增了2个生命周期钩子,废除的生命周期钩子仍然能够使用,但是控制台会出现警告,在17版本以后这些生命周期钩子必须加上UNSAFE_的前缀才能消除这些警告。

废除的生命周期钩子:

  1. UNSAFE_componentWillMount
  2. UNSAFE_componentWillReceiveProps
  3. UNSAFE_componentWillUpdate

为什么要废除这些生命周期钩子?

首先UNSAFE前缀并不是说这些生命周期钩子不安全,而是React官方在未来会开发一种叫异步渲染的技术,而这之前很多开发者有滥用这些生命周期钩子的情况,而这种情况会在未来新开发的“异步渲染”的技术中会引起很多的问题,所以React官方在这几个生命周期钩子前增加了前缀,增加了开发者使用这些生命周期钩子的成本,在未来这几个生命周期钩子可能会被废除。

新增的生命周期钩子:

  1. getDerivedStateFromProps

    使用方法:static getDerivedStateFromProps(props, state)

    参数:

    • props:组件即将用来渲染的下一个props
    • state:组件即将渲染的下一个state

    如果你定义了 static getDerivedStateFromPropsReact 会在初始挂载和后续更新时调用 render 之前调用它。它应该返回一个对象来更新 state,或者返回 null 就不更新任何内容。

    此方法适用于 少数罕见用例,其中 state 取决于 props 随着时间的推移的变化。

  2. getSnapshotBeforeUpdate

    使用方法:getSnapshotBeforeUpdate(prevProps, prevState)

    参数:

    • prevProps:更新之前的 PropsprevProps 将会与this.props进行比较来确定发生了什么改变。
    • prevState:更新之前的 StateprevState 将会与this.state 进行比较来确定发生了什么改变。

    如果你实现了 getSnapshotBeforeUpdateReact 会在 React 更新DOM之前时直接调用它。它使你的组件能够在 DOM 发生更改之前捕获一些信息(例如滚动的位置)。此生命周期方法返回的任何值都将作为参数传递给 componentDidUpdate

    例如,你可以在像是需要在更新期间保留其滚动位置的聊天消息的UI中来使用它。

新的生命周期流程图:

react生命周期(新).png