React 生命周期(v16.4)
React v16.4 的生命周期
React v16.4 的生命周期
变更缘由
原来(React v16.0前)的生命周期在React v16推出的Fiber之后就不合适了,因为如果要开启async rendering,在render函数之前的所有函数,都有可能被执行多次。
原来(React v16.0前)的生命周期有哪些是在render前执行的呢?
- componentWillMount
- componentWillReceiveProps
- shouldComponentUpdate
- componentWillUpdate
如果开发者开了async rendering,而且又在以上这些render前执行的生命周期方法做AJAX请求的话,那AJAX将被无谓地多次调用。。。明显不是我们期望的结果。而且在componentWillMount里发起AJAX,不管多快得到结果也赶不上首次render,而且componentWillMount在服务器端渲染也会被调用到(当然,也许这是预期的结果),这样的IO操作放在componentDidMount里更合适。
禁止不能用比劝导开发者不要这样用的效果更好,所以除了shouldComponentUpdate,其他在render函数之前的所有函数(componentWillMount,componentWillReceiveProps,componentWillUpdate)都被getDerivedStateFromProps替代。
也就是用一个静态函数getDerivedStateFromProps来取代被deprecate的几个生命周期函数,就是强制开发者在render之前只做无副作用的操作,而且能做的操作局限在根据props和state决定新的state
React v16.0刚推出的时候,是增加了一个componentDidCatch生命周期函数,这只是一个增量式修改,完全不影响原有生命周期函数;但是,到了React v16.3,大改动来了,引入了两个新的生命周期函数。
新引入了两个新的生命周期函数:getDerivedStateFromProps
,getSnapshotBeforeUpdate
getDerivedStateFromProps
getDerivedStateFromProps
本来(React v16.3中)是只在创建和更新(由父组件引发部分),如果不是由父组件引发,那么getDerivedStateFromProps也不会被调用,如自身setState引发或者forceUpdate引发。
React v16.3 的生命周期图
React v16.3
这样的话理解起来有点乱,在React v16.4中改正了这一点,让getDerivedStateFromProps无论是Mounting还是Updating,也无论是因为什么引起的Updating,全部都会被调用,具体可看React v16.4 的生命周期图。
React v16.4后的getDerivedStateFromProps
static getDerivedStateFromProps(props, state) 在组件创建时和更新时的render方法之前调用,它应该返回一个对象来更新状态,或者返回null来不更新任何内容。
getSnapshotBeforeUpdate
getSnapshotBeforeUpdate() 被调用于render之后,可以读取但无法使用DOM。它使您的组件可以在可能更改之前从DOM捕获一些信息(例如滚动位置)。此生命周期返回的任何值都将作为参数传递给componentDidUpdate()。
官网给的例子:
class ScrollingList extends React.Component {
constructor(props) {
super(props);
this.listRef = React.createRef();
}
getSnapshotBeforeUpdate(prevProps, prevState) {
//我们是否要添加新的 items 到列表?
// 捕捉滚动位置,以便我们可以稍后调整滚动.
if (prevProps.list.length < this.props.list.length) {
const list = this.listRef.current;
return list.scrollHeight - list.scrollTop;
}
return null;
}
componentDidUpdate(prevProps, prevState, snapshot) {
//如果我们有snapshot值, 我们已经添加了 新的items.
// 调整滚动以至于这些新的items 不会将旧items推出视图。
// (这边的snapshot是 getSnapshotBeforeUpdate方法的返回值)
if (snapshot !== null) {
const list = this.listRef.current;
list.scrollTop = list.scrollHeight - snapshot;
}
}
render() {
return (
<div ref={this.listRef}>{/* ...contents... */}</div>
);
}
经典的react生命周期流程图
左边是单个组件生命周期,右边是多组件交互时组件的生命周期。
-
十个生命周期包含:
初始化阶段
- getDefaultProps
- getInitialState
- componentWillMount
- render
- componentDidMount
运行中状态阶段
- componentWillReciveProps
- shouldComponentUpdate
- componentWillUpdate
- componentDidUpdate
销毁阶段
- componentWillUnmount
// parent
import React,{Component} from 'react'
import Child from './Child'
import {Button,Input} from 'antd'
import './index.less'
export default class Life extends Component{
// constructor(props) {
// super(props);
// this.state = {
// count:0
// };
// }
// 等价于上面
state = {
count:0
}
// 箭头函数this指向组件实例
handleAdd=()=>{
this.setState({
count: this.state.count + 1
})
}
// 非箭头函数This指向取决于调用者,这里会指向dom对象
handleClick(){
this.setState({
count: this.state.count + 1
})
}
render(){
// react里面style=,外面括号是react语法,内部括号代表是对象
let style = {
padding:200
}
return <div className="content" style={style}>
<p>React生命周期介绍</p>
<Input></Input>
<Button onClick={this.handleAdd} type="primary">AntD点击一下</Button>
<button onClick={this.handleAdd}>点击一下</button>
<button onClick={this.handleClick.bind(this)}>点击一下</button>
<p>{this.state.count}</p>
<Child name={this.state.count}></Child>
</div>
}
}
// child
import React from 'react'
export default class Child extends React.Component {
constructor(props) {
super(props);
// state只是用于组件自身管理状态
this.state = {
count: 0
};
}
componentWillMount(){
console.log('will mount');
}
componentDidMount(){
console.log('did mount');
}
componentWillReceiveProps(newProps){
console.log('will props' + newProps.name)
}
shouldComponentUpdate(){
console.log('should upate')
return true;
}
componentWillUpdate(){
console.log('will upate')
}
componentDidUpdate(){
console.log('did upate')
}
render(){
return <div>
<p>这里是子组件,测试子组件的生命周期</p>
<p>{this.props.name}</p>
</div>
}
}