生命周期 (新)
初始化阶段
constructor()
类的默认方法,在类中是必须存在的,里边的super()
方法是必须的,如果没有定义constructor()
,会默认生成一个空的构造器constructor
挂载阶段
(componentWillMount() ->) render() -> componentDidMount()
(componentWillMount()
❌:组件挂载之前调用,很少使用, 17.0 版本将会删除)
-
render()
:是组件中必须定义的,用来渲染DOM,并必须return
一个React元素(描述组件,即UI) -
componentDidMount()
: 组件完成后调用 ,componentDidMount在渲染过程中永远只有执行一次,一般是在componentDidMount执行副作用,进行异步操作,并在异步请求中可以进行setState
;也可以在这里使用refs,获取真实dom元素。
更新阶段
但凡
state
和props
发生更新,不管是否改变,都会引起子组件重新render
static getDerivedStateFromProps(nextProps, prevState) -> shouldComponentUpdate(nextProps,nextState) -> getSnapshotBeforeUpdate(prevProps, prevState) -> componentDidUpdate(prevProps, prevState)
static getDerivedStateFromProps(nextProps, prevState)
✅v16.4新增加的生命周期nextProps
表示更新后的 props,prevState
表示更新前的 state- 根据
nextProps
和prevState
计算出预期的状态改变,返回结果会被送给setState
,也就是说我们可以根据props
,state
的变化情况来决定返回情况 - ⚠️这个生命周期函数是一个静态函数,因此是无法访问实例的属性和方法的(就不能使用
this
啦 - 返回值如果是
object
,就相当于是setState
操作;如果是null或者其他基本类型,就不会更新state
,没有返回值会报错 - 这是一个例子🌰:
static getDerivedStateFromProps(nextProps, state) {
const param = nextProps.search.substring(1)
if (param !== state.param) {
return {
param,
loading: true
}
}
return null;
};
(componentWillReceiveProps(nextProps )❌17.0 版本将会删除)
shouldComponentUpdate(nextProps,nextState)
- 通过比较
nextProps
,nextState
及当前组件的this.props
,this.state
的状态用来判断是否需要重新渲染 - 默认返回
true
,需要重新render
,返回false
则不触发渲染。 - 可以用来优化组件性能
- 通过比较
getSnapshotBeforeUpdate(prevProps, prevState)
✅v16.4新增加的生命周期- 作用是在真实 DOM 更新(
componentDidUpdate
)前,获取一些需要的信息(类似快照功能),然后作为参数传给componentDidUpdate
prevProps
表示更新前的 props,prevState
表示更新前的 state- 返回值是一个快照(Snapshot),如果返回null就表示不生成快照,若有有效返回值,返回值会作为
componentDidUpdate(prevProps, prevState)
第三个参数 - ⚠️这个生命周期函数必须和
componentDidUpdate(prevProps, prevState)
同时使用,否则报错 - 这是一个例子🌰:
- 作用是在真实 DOM 更新(
getSnapshotBeforeUpdate() {
// 返回更新内容的高度 300px
return this.wrapper.current.scrollHeight;
}
componentDidUpdate(prevProps, prevState, prevScrollHeight) {
this.wrapper.current.scrollTop =
this.wrapper.current.scrollTop +
(this.wrapper.current.scrollHeight - prevScrollHeight);
}
(componentWillUpdate(nextProps,nextState)❌17.0 版本将会删除)
-
componentDidUpdate(prevProps, prevState)
- 可以操作组件更新的DOM,
prevProps
和prevState
这两个参数指的是组件更新前的props
和state
- 这个函数内要谨慎的使用
setState
,使用该钩子内setState
有可能会触发重复渲染,需要自行判断,否则会进入死循环。下图就是无条件使用setState
时产生的错误:
在componentDidMount
里面setState
导致组件更新,组件更新后会执行componentDidUpdate
,此时你又在componentDidUpdate
里面setState
又会导致组件更新,造成成死循环了
- 可以操作组件更新的DOM,
卸载阶段
componentWillUnmount()
组件卸载前调用,经常用来执行一些清理操作,比如清理定时器,取消订阅等等来避免内存泄漏。
注意⚠️
- 新的生命周期函数不可以🚫和即将废弃的两个函数同时使用
getDerivedStateFromProps
并不是只会在props
“改变”时才会调用。实际上只要父组件重新渲染时,这个生命周期函数就会重新调用,不管props
有没有“变化”
下面是一个例子🌰:
import React, { Component } from 'react'
export default class LifeCycle extends Component {
props = {age:10,name:'计数器'}
static defaultProps = {
name:'计数器'
}
constructor(props){
//Must call super constructor in derived class before accessing 'this' or returning from derived constructor
super();//this.props = props;
this.state = {number:0,users:[]};//初始化默认的状态对象
console.log('1. constructor 初始化 props and state');
}
//componentDidMount在渲染过程中永远只有执行一次
//一般是在componentDidMount执行副作用,进行异步操作
componentDidMount(){
console.log('3. componentDidMount 组件挂载完成');
fetch('https://api.github.com/users').then(res=>res.json()).then(users=>{
console.log(users);
this.setState({users});
});
}
shouldComponentUpdate(nextProps,nextState){
console.log('Counter',nextProps,nextState);
console.log('4. shouldComponentUpdate 询问组件是否需要更新');
return true;
}
componentDidUpdate(prevProps, prevState)){
console.log('5. componentDidUpdate 组件更新完毕');
}
add = ()=>{
this.setState({number:this.state.number});
};
render() {
console.log('2.render渲染,也就是挂载')
return (
<div style={{border:'5px solid red',padding:'5px'}}>
<p>{this.props.name}:{this.state.number}</p>
<button onClick={this.add}>+</button>
<ul>
{
this.state.users.map(user=>(<li>{user.login}</li>))
}
</ul>
{this.state.number%2==0&&<SubCounter number={this.state.number}/>}
</div>
)
}
}