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比父组件先执行。