学习笔记——react的生命周期钩子函数


react的生命周期大体分为三个阶段:组件创建,组件更新,组件销毁。并且只有类组件才具有生命周期的钩子函数,函数组件没有。

图1.react生命周期钩子函数

1.组件创建: 

图1展示了生命周期的钩子函数执行的顺序。

1.constructor():

可以通过this.state赋值对象来初始化数据。

为事件处理函数绑定实例。

constructor(props) {
    super(props);
    this.state = {
        a: 10,
        b: 100
   };
   this.changeName = this.changeName.bind(this);
}

只在组件创建时执行一次,其后不再执行。

2.static getDerivedStateFromProps():

该函数用来为作为子组件的组件赋初始值,并且该组件可以修改自己state中的数据。

函数内部通常要作判断,如果本组件修改了自身state中的数据,就不需要父组件传来的props中的数据。

在组件创建和更新阶段都会调用。

内无this指针,有两个参数,第一个参数是父组件传来的props中的数据,第二个参数是本组件state中的数据。

必须return一个对象或null。如果是对象,则会合并到本组件的state中去。

static getDerivedStateFromProps(nextProps, prevState) {
    if(nextProps.b !== prevState.prevProps.b) {
        return {
            b: nextProps.b,
            prevProps: { b: nextProps.b }
        };
    }else
        return null;
}

3.componentWillMount() || UNSAFE_componentWillMount():

在此函数中调用setState不会触发额外的渲染。但是该功能可以在constructor中直接实现。所以该函数没有什么意义,已经基本处于废弃状态。

4.render(): 

渲染页面的主要地方,其中可以实现一些操作,但是必须返回一个jsx对象。

核心代码,会反复调用,减少不必要的render()函数调用次数可以实现性能优化。

render() {
    // 核心代码,会被反复调用
    console.log("render函数运行了");
    return (
        <div>这是个人中心
            <Child b ={this.state.b}></Child>
        </div>
    );
}

 5.componentDIdMount():

会在组件挂载后调用。组件挂载也就是插入dom树中。

在该函数中,通常会发送ajax请求组件所需要的动态数据。

在这里调用setState会触发render()函数。

componentDidMount() {
    // 组件挂载完毕
    let listMain = await http("/category/list/0");
    this.setState({  listMain });
    this.changeCategory(listMain[0].id);
}

 2.组件更新:

如何触发组件的更新:

1.本组件自身调用setState,会触发re-render(重新渲染)。

2.父组件触发re-render,子组件连带着被re-render。

3.props改变了,会触发本组件re-render。

1.componentWillReceiveProps() || UNSAFE_componentWillReceiveProps():

该组件在组件更新时调用,通常用来:当props值发生改变时,在该函数中做相应操作,以响应props值得改变。

该组件已基本被废弃。可以在componentDidUpdate中做相应的操作。

2.static getDerivedStateFromProps():

与组件创建时一样操作。详情见组件创建。

3.shouldComponentUpdate():

该函数主要用来对reacr进行性能优化。

该函数必须显示的返回一个true或false。

两个参数,第一个参数为nextProps: 马上要生效的props值,第二个参数为nextState:马上要生效的state值。获取现在的值为this指针。

写出合理的逻辑,减少不必要的更新。如果return false; 就不会向下执行,也就减少了render次数,优化了性能。

shouldComponentUpdate(nextProps){
    console.log("child组件的shouldComponentUpdate运行了");
    return this.props.b !== nextProps.b;
}

// 如果不写默认返回true

进行render优化的代码如下:

shouldComponentUpdate(nextProps){
    let keys = Object.keys(nextProps);
    for(let i = 0; i < keys.length; i++) {
        if(this.props[keys[i]] !== nextProps[keys[i]] ) return true;
    }
    return false;
}

 就相当于继承自react的pureComponent的类组件默认的shouldComponentUpdate()函数一样。 

import React, {PureComponent} from 'react';

class Child extends PureComponent {}

PureComponent比较props中的所有属性,优先决定当前组件是否需要re-render。

但是:PureComponent只做简单的属性值“浅比较”。

浅比较对于值类型还可以,对于引用类型只会比较它们在内存中的地址是否相同,不会进行深层次的比较。

若传过来一个地址不同,内容相同的引用类型,PureComponent无法进行深层次比较。

使用情况:当知道一个组件是类组件,并且这个类组件需要做性能优化。

最大的坑:父组件向子组件传引用类型的数据时,不能直接在传值的时候进行绑定。例如: 

// 错误写法
<Child b ={this.state.b} changeName={this.changeName.bind(this)}></Child>

// 正确写法
changeName = () => {};
<Child b ={this.state.b} changeName={this.changeName}></Child>

4.componentWillUpdate() ||  UNSAFE_componentWillUpdate():

该方法已被废弃,可以用componentDidUpdate()代替该函数的功能。

如果需要读取dom信息,则可以用getSnapshotBeforeUpdate代替。

componentWillUpdate(){
    // 基本废弃,一般不用了。改名了UNSAFE_componentWillUpdate
    console.log("componentWillUpdate函数运行了");
}

5.render():

更新阶段渲染,可以根据新的数据渲染组件的dom节点。dom节点会与上次相比,找出不一样的节点进行修改。不是全部重新渲染dom节点。

6.getSnapshotBeforeUpdate():

在该函数中一般执行一些dom操作。记录滚动位置。

例如:可以滚动的页面,突然刷新后,需要在本函数中记录其位置,然后传给componentDidUpdate()函数,可以在更新结束后,重新回到该位置。

有两个参数:prevProps,prevState其内容同上。

需要返回一个值return

getSnapshotBeforeUpdate(prevProps, prevState){
    return { y: 50 }
}
componentDidUpdate(prevProps, prevState, snapshot){
    console.log(snapshot) // { y: 50 }
}

7.componentDidUpdate():

该函数主要在更新完成时执行。

共有两个参数:第一个参数为prevProps,更新前的props值,第二个参数表示更新前的state中的值。当前值为this.props。第三个参数为getSnapshotBeforeUpdate()传过来的数据。

实现类似vue中的watch监听。通过比较更新前和更新后的数据。

这个函数表示最新的state对应的dom更新完毕,所以可以对最新的dom做一些自定义操作。

// 模拟vue中的watch监听
componentDidUpdate(prevProps,prevState) {
    if(prevState.a !== this.state.a) {
        console.log("a变量");
    }
}

// 对最新的dom做些自定义操作
// 例如使用插件监听滚动

3.组件销毁:

不再使用,或者长时间不使用的组件需要销毁操作。

1.componentWillUnmount():

 该函数主要用来释放相关的内存空间和资源。

// 组件销毁
componentWillUnmount() {
    // 释放当前组件相关的内存和资源
    console.log("componentWillUnmount运行了")
}

以上就是react中的生命周期的钩子函数,通过不同函数可以实现不同的功能。

父组件和子组件中生命周期钩子函数的执行顺序如下:

父组件的constructor,render函数比子组件先执行,子组件的componentDidMount,componentDidUpdate比父组件先执行。

猜你喜欢

转载自blog.csdn.net/qq_41339126/article/details/109504150