认识到的React生命周期分为React16.0 之前的生命周期和React16.0之后的生命周期
React16.0 版本之前的生命周期
static defaultProps = {};
static propTypes = {};
constructor(props) {
super(props);
this.state = {};
}
componentWillMount() {}
render() {}
componentDidMount() {}
组件运行时
constructor(props) {
super(props);
// 常用于初始化状态
console.log("1.组件构造函数执行");
}
componentWillMount() {
// 此时可以访问状态和属性,可进行api调用等
console.log("2.组件将要挂载");
}
componentDidMount() {
// 组件已挂载,可进行状态更新操作
console.log("3.组件已挂载");
}
componentWillReceiveProps(nextProps) {
// 父组件传递的属性有变化,做相应响应
console.log("4.将要接收属性传递");
}
shouldComponentUpdate(nextProps, nextState) {
// 组件是否需要更新,需要返回布尔值结果,优化点
console.log("5.组件是否需要更新?");
return true;
}
componentWillUpdate(nextProps, nextState) {
// 组件将要更新,可做更新统计
console.log("6.组件将要更新");
}
componentDidUpdate(prevProps, prevState) {
// 组件更新
console.log("7.组件已更新");
}
componentWillUnmount() {
// 组件将要卸载, 可做清理工作
console.log("8.组件将要卸载");
}
render() {
console.log("组件渲染");
return <div>生命周期探究</div>;
}
- 只有在 render 和 componentDidUpdate 中才能获取到更新后的 this.state
- 在函数(componentWillReceiveProps)中调用 this.setState() 将不会引起第二次渲染
- 禁止在 shouldComponentUpdate 和 componentWillUpdate 中调用 setState,这会造成循环调用,直至耗光浏览器内存后崩溃。
组件的生命周期在不同状态下的执行顺序
-
当首次挂载组件时,按顺序执行
getDefaultProps、getInitialState、componentWillMount、render 和
componentDidMount -
当卸载组件时,执行 componentWillUnmount 当重新挂载组件时,此时按顺序执行
getInitialState、componentWillMount、render 和componentDidMount,但并不执行
getDefaultProps -
当再次渲染组件时,组件接受到更新状态,此时按顺序执componentWillReceiveProps、shouldComponentUpdate、componentWillUpdate、render 和 componentDidUpdate
当使用 ES6 classes 构建 React 组件时,static defaultProps = {} 其实就是调用内部的 getDefaultProps方法,constructor 中的 this.state = {} 其实就是调用内部的 getInitialState 方法
React16.4 的生命周期
- getDerivedStateFromProps
React v16.3 getDerivedStateFromProps无论是Mounting还是Updating,也无论是因为什么引起的Updating,全部都会被调用
React v16.4 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>
);
}
}
constructor(props) {
super(props);
this.state = {
visible: false,
}
console.log('constructor')
}
// 初始化/更新时调用
static getDerivedStateFromProps(props, state) {
console.log('getDerivedStateFromProps', props, state);
return state
}
// 初始化渲染时调用
componentDidMount() {
console.log('componentDidMount');
}
// 组件更新时调用
shouldComponentUpdate(nextProps, nextState) {
console.log('shouldComponentUpdate', nextProps, nextState)
}
// 组件更新时调用
getSnapshotBeforeUpdate = (prevProps, prevState) => {
console.log('getSnapshotBeforeUpdate', prevProps, prevState);
}
// 组件更新后调用
componentDidUpdate(prevProps, prevState) {
console.log('componentDidUpdate', prevProps, prevState);
}
// 组件卸载时调用
componentWillUnmount() {
console.log('componentWillUnmount');
}
render() {
console.log('render');
return (
<div></div>
)
}
文章参考:
1、From TaobaoFED 【I like his website】高性能 React 组件
http://taobaofed.org/blog/2016/08/12/optimized-react-components/
2、什么时候要在 React 组件中写 shouldComponentUpdate
https://infoq.cn/article/2016/07/react-shouldComponentUpdate
3、【喜欢这篇文章讲解的生命周期】 react如何通过shouldComponentUpdate来减少重复渲染
https://segmentfault.com/a/1190000016494335