# 类组件生命周期方法

# 各个生命周期方法的作用

# constructor

可以在 constructor 方法中,做一些初始化的工作,比如初始化状态、绑定方法等等。

# getDerivedStateFromProps

官方介绍: static getDerivedStateFromProps(props, state) (opens new window)

这个方法会在 render 函数执行之前调用,且在初始化挂载和后续更新时都会被调用,这个方法内部是访问不到 this 的。

import React, { Component } from 'react';

export default class Demo extends Component {
	static getDerivedStateFromProps() {}

	render() {
		return 1;
	}
}

上面这样使用会报错:

使用的时候一定要初始化一个状态,并且返回一个对象,它返回值将作为新的 state 合并到 state 中。

import React, { Component } from 'react';
export default class Demo extends Component {
	state = {
		age: 18
	};
	static getDerivedStateFromProps(nextProps, prevState) {
		console.log(nextProps, prevState);
		/* 
    第一次渲染时的输出:
    {} {age: 18}

    age更新后的输出:
    {} {age: 19, name: "f"}
    */
		return { name: 'f' };
	}

	shouldComponentUpdate(nextProps, nextState) {
		console.log(nextState);
		return true;
	}

	componentDidMount = () => {
		setTimeout(() => {
			this.setState({
				age: 19
			});
		}, 5000);
	};

	render() {
		return (
			<div>
				<span>{JSON.stringify(this.state)}</span>
			</div>
		);
	}
}

getDerivedStateFromProps 作用:

  • 替代 componentWillMount 和 componentWillReceiveProps;
  • 根据最新的 props 计算 state;

# UNSAFE_componentWillMount

这个方法会在 render 函数执行之前被调用,这个方法未来可能会被废弃,所以不建议在里面写什么代码。

# UNSAFE_componentWillReceiveProps

一般是在子组件的 props 发生改变后会触发 UNSAFE_componentWillReceiveProps ,但是像下面这个代码,子组件中的 props 并没有发生改变,浏览器控制台还是打印了 'componentWillReceiveProps',这是为什么呢?

import React, { Component } from 'react';

class Child extends Component {
	componentWillReceiveProps = (nextProps) => {
		console.log('componentWillReceiveProps');
	};

	render() {
		return 'child';
	}
}
export default class Deom extends Component {
	state = {
		age: 16
	};

	componentDidMount = () => {
		setTimeout(() => {
			this.setState({
				age: 17
			});
		}, 2000);
	};

	render() {
		return <Child />;
	}
}

这是因为当父组件中的 state 发生变化的时候,会触发父组件的 render 函数执行,会调用 React.createElement 方法,重新创建 props,所以子组件中的 componentWillReceiveProps 会重新执行。

# getSnapshotBeforeUpdate

getSnapshotBeforeUpdate(prevProps,preState) 方法主要用来获取一次更新前的信息,并这个信息传递给 componentDidUpdate 方法的第三个参数。

getSnapshotBeforeUpdate(prevProps,preState) 需要和 componentDidUpdate 配合使用。

import React, { useEffect, useState, Component } from 'react';

export default class Deom extends Component {
	getSnapshotBeforeUpdate() {}
	render() {
		return 1;
	}
}

上面这样写会报警告:

# 函数组件中的生命周期替代方案

在函数组件中我们可以通过 useEffect (opens new window) 或者 useLayoutEffect (opens new window) 来模拟类组件中的生命周期。

useEffect 的函数会在浏览器完成布局与绘制之后,在一个延迟事件中被调用。

useLayoutEffect 它会在所有的 DOM 变更之后同步调用 effect。可以使用它来读取 DOM 布局并同步触发重渲染。

# 代替 componentDidMount

React.useEffect(()=>{
  /* 请求数据 , 事件监听 , 操纵dom */
},[])  /* 切记 dep = [] */

# 代替 componentWillUnmount

 React.useEffect(()=>{
  /* 请求数据 , 事件监听 , 操纵dom , 增加定时器,延时器 */
  return function componentWillUnmount(){
      /* 解除事件监听器 ,清除定时器,延时器 */
  }
},[])/* 切记 dep = [] */

# 代替 componentWillReceiveProps

React.useEffect(()=>{
    console.log('props变化:componentWillReceiveProps')
},[ props ])

# 代替 componentDidUpdate

React.useEffect(()=>{
    console.log('组件更新完成:componentDidUpdate ')     
}) /* 没有 dep 依赖项 */

useEffect 在初始化的时候会默认执行一次,但是 componentWillReceiveProps、componentDidUpdate 只有在依赖改变的时候才会执行。

# 问答

# 为什么componentWillMount会有执行多次的可能呢?

因为 render 过程会被优先级更高的打断。

# 当 props 不变的前提下, PureComponent 组件能否阻止 componentWillReceiveProps 执行?

componentWillReceiveProps 生命周期的执行,和纯组件没有关系,纯组件是在 componentWillReceiveProps 执行之后浅比较 props 是否发生变化。所以 PureComponent 下不会阻止该生命周期的执行。