React17 生命周期
在17版本中
- 废除的生命周期有:
componentWillMount
,componentwillReceiveProps
,componentWillUpdate
- 新增的生命周期有:
getDerivedStateFromProps(nextProps, prevState)
.
生命周期顺序
Mounting 挂载顺序(初始化)
constructor(props)
:初始化 state 和 props 数据- 新增
static getDerivedStateFromProps(nextProps, prevState)
:组件初始化和被更新时调用
用来替代componentWillMount()
在组件即将被挂载到页面时执行(16.3已废弃) render()
:渲染组件componentDidMount()
:在组件被挂载到页面后执行,只在挂载时执行一次
Updation 更新顺序(更新)
static getDerivedStateFromProps(nextProps, prevState)
:组件初始化和被更新时调用shouldComponentUpdate(nextProps, nextState)
:在组件被更新之前执行 (return true 更新 , return false 不更新)render()
: 渲染页面static getSnapshotBeforeUpdate(prevProps, prevState)
componentDidUpdate()
:state或props更新后调用
Unmounting 卸载(销毁)
componentWillUnmount()
:在组件即将被页面剔除时执行
注意
除了render函数,其他所有的生命周期函数都可以没有
生命周期详解
1. constuctor
初始化 state 和 props 数据:
- 组件的初始化,用来定义当前组件所需要的一些状态,状态定义在
this.state
中; - 当前生命周期中必须书写
super
,否则this
的指向会发生错误以及报错; - 在当前生命周期中默认是访问不到
props
属性的,如果想要进行访问必须在super
以及constructor
中添加参数props
import { Component } from 'react';
import store from './store/index';
class List extends Component {
constructor(props) {
super(props);
this.state = store.getState();
store.subscribe(this.storeChange.bind(this)); // store发生改变时,自动触发
}
storeChange() {
this.setState(store.getState());
}
}
2. componentWillMount(废弃)
组件即将被挂载到页面前:
- 可以进行前后端数据的请求(在服务端渲染的时候)
- 可以在数据第一次被渲染的时候做数据的更改
- 在当前生命周期中尽量不要调用
this.setState
因为当前生命周期函数执行完毕后,会自动执行render
函数 - 可以将外部的数据转换为内部的数据
3. static getDerivedStateFromProps(新增)
static getDerivedStateFromProps(nextProps,prevState)
:接收父组件传递过来的 props 和组件之前的状态,返回一个对象来更新 state 或者返回 null 来表示接收到的 props 没有变化,不需要更新 state ;- 该生命周期钩子的作用: 将父组件传递过来的 props 映射 到子组件的 state 上面,这样组件内部就不用再通过
this.props.xxx
获取属性值了,统一通过this.state.xxx
获取。映射就相当于拷贝了一份父组件传过来的 props ,作为子组件自己的状态。注意:子组件通过 setState 更新自身状态时,不会改变父组件的 props; - 配合
componentDidUpdate
,可以覆盖componentWillReceiveProps
的所有用法;
注意:
getDerivedStateFromProps
前面要加上static保留字,声明为静态方法,不然会被react忽略掉getDerivedStateFromProps
里面的this
为undefined
.
4. render
- 当前生命周期用来进行数据与模板的结合
- render 函数第一次执行的时候会将渲染的数据在内存中保存一份,当第二次数据发生了改变后,render 会将这次的虚拟DOM与缓存中的虚拟DOM进行对比(diff 算法)
- 只要
this.state
、this.props
发生了改变那么 render 函数就会执行
render() {
return (
<input id="input" type="text" value={this.state.value} onChange={this.change.bind(this)} />
);
}
5. componentDidMount
在组件被挂载到页面后执行,只在挂载时执行一次:
-
当前生命周期我们可以做前后端数据的交互
-
可以在当前生命周期中获取到真实的DOM 通过
this.refs
来获取 -
一般情况下我们都在当前生命周期中做一些插件的实例化
版本迁移
-
componentWillMount
,componentWillReceiveProps
,componentWillUpdate
这三个生命周期因为经常会被误解和滥用,所以被称为 不安全的生命周期(不是指安全性,而是表示使用这些生命周期的代码,有可能在未来的 React 版本中存在缺陷,可能会影响未来的异步渲染) -
React 16.3 版本:为不安全的生命周期引入别名
UNSAFE_componentWillMount
,UNSAFE_componentWillReceiveProps
和UNSAFE_componentWillUpdate
。(旧的生命周期名称和新的别名都可以在此版本中使用) -
React 16.3 之后的版本:为
componentWillMount
,componentWillReceiveProps
和componentWillUpdate
启用弃用警告。(旧的生命周期名称和新的别名都可以在此版本中使用,但旧名称会记录DEV模式警告) -
React 17.0 版本: 推出新的渲染方式——异步渲染(
Async Rendering
),提出一种可被打断的生命周期,而可以被打断的阶段正是实际 dom 挂载之前的虚拟 dom 构建阶段,也就是要正式废弃三个生命周期componentWillMount
,componentWillReceiveProps
和componentWillUpdate
。(从这个版本开始,只有新的“UNSAFE_”生命周期名称将起作用)
import { Component } from 'react';
export default class LifeCycle extends Component {
constructor(props) {
super(props);
this.state = { number: 0 }; // 初始化默认的状态对象
console.log('1. constructor 初始化props和state');
}
// componentWillMount() {
// console.log('2. componentWillMount 组件将要挂载');
// }
static getDerivedStateFromProps(nextProps, prevState) {
console.log('2. getDerivedStateFromProps');
const { list } = nextProps;
// 当传入的list发生变化的时候,更新state
if (list !== prevState.list) {
return {
list,
};
}
// 否则,对于state不进行任何操作
return null;
}
render() {
console.log('3. render 渲染');
return (
<div>
<p>{this.state.number}</p>
<button onClick={this.add}>+</button>
</div>
);
}
componentDidMount() {
console.log('4. componentDidMount 组件挂载完成');
}
shouldComponentUpdate(nextProps, nextState) {
console.log('5. shouldComponentUpdate 询问组件是否需要更新');
return true;
}
// componentWillUpdate() {
// console.log('6. componentWillUpdate 组件将要更新');
// }
componentDidUpdate() {
console.log('6. componentDidUpdate 组件更新完毕');
}
add = () => {
this.setState({ number: this.state.number + 1 });
};
}