React 组件的生命周期
每一个 React 组件的实例都拥有着一套完善的生命周期,主要分为挂载、更新和卸载三个大阶段,每一个阶段都拥有着更为细化的生命周期。
三个阶段与相关 API

挂载
挂载阶段相关的生命周期 API:
static getDefaultPropsinitialize stateconstructor(props)static getDerivedStateFromProps(nextProps, prevState)(V 16.3.0)componentWillMount()/UNSAFE_componentWillMount()render()componentDidMount()
更新
更新阶段相关的生命周期 API:
componentWillReceiveProps(nextProps)/UNSAFE_componentWillreceiveProps(nextProps)static getDerivedStateFromProps(nextProps, prevState)(V 16.3.0)shouldComponentUpdate(nextProps, nextState)componentWillUpdate(nextProps, nextState)/UNSAFE_componentWillUpdate(nextProps, nextState)render()getSnapshotBeforeUpdate(prevProps, prevState)(V 16.3.0)componentDidUpdate(prevProps, prevState, snapshot)
卸载
卸载阶段相关的生命周期 API:
componentWillUnmount()
API 详情
static getDefaultProps
定义默认属性
class MyComponent extends React.Component {
static getDefaultProps = {}
// ...
}initialize state
初始化 state。
当前版本的官方文档(V 16.3.0)未说明该阶段。在 React V 16.0.0 之前,React.createClass 仍未废弃的情况下,还包含着这个阶段相关的 api。当前的官方文档中的示例,初始化
state都是在constructor中完成。但是文档中说到_(The constructor is the right place to initialize state. _To do so, just assign an object to _this.state),_猜测实际上仍存在该阶段
class MyComponent extends React.Component {
// ES7 语法实现初始化 state
state = {}
// ...
}constructor(props)
构造器函数,在此阶段进行初始化 state 和事件处理器(event handler)的上下文绑定
React.Component的子类的构造器函数里,一定得调用super(props),否则this.props将会是undefined不要在这个阶段调用this.setState(),倘若要改变 state,只需要 state 对象进行 assign 操作即可
如果,不需要初始化 state 也不打算给 class 实例绑定,事件处理器,就没有必要实现
conostructor在此阶段改变 state 时,不处理受到 props 影响的值,而是在
componentWillMount或getDerivedStateFrom内处理
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {};
this.btnClickHandler = this.btnClickHandler.bind(this);
}
btnClickHandler (e) {}
// ...
}static getDerivedStateFromProps(nextProps, prevState)
React v16.3.0新增 API。getDerivedStateFromProps()在组件初始化和接收新的 props 时调用。将会返回一个 object 去更新 state,或是返回一个null表示新的 props 不会导致 state 更新。
无论 props 是否改变,该函数都会被调用
通常情况下,
this.setState()不会触发该函数一旦使用了这个新的生命周期函数,不安全的生命周期函数将不会被调用
class MyComponent extends React.Component {
static getDerivedStateFromProps(nextProps, prevState) {
if (nextProp.value !== prevState.selectedVal) {
return {
selectedVal: nextProps.value,
}
}
return null;
}
// ...
}UNSAFE_componentWillMount()
componentWillMount() 的别名。在即将挂载的时候调用。由于该阶段在render之前,因此,在该阶段异步的调用setState()不会触发额外的渲染。在挂载之前,最后一次允许改变 state 的阶段。
componentWillMount这个名称计划在 React V17.0.0 之后废弃掉。react 提供了 rename-unsafe-lifecycles codemod 这个工具去自动更新该生命周期函数会受到
static getDerivedStateFromProps()和getSnapshotBeforeUpdate()的影响而无法使用
class MyComponent extends React.Component {
UNSAFE_componentWillMount() {
if (this.props.mod === 'mod1') {
this.setState({
mod1State
});
}
}
// ...
}componentDidMount()
componentDidMount()在挂载完成后调用。在该阶段可进行加载远程数据,订阅事件,设置定时器等操作。
该阶段调用 setState() 会触发额外的渲染,处理不当可能会导致死循环
class MyComponent extends React.Component {
_loadData() { // ... }
componentDidMount() {
this._loadData();
this.autoLoadDataIntevalKey = setInterval(this._loadData, 30 * 1000);
this.subscriptKey = subscriptNoticeMsg((msg) => {
alert(msg);
});
}
// ...
}UNSAFE_componentWillReceiveProps(nextProps)
componentWillReceiveProps()的新名称,在一个已经挂载的组件接收到新 props 时被调用。如果需要在此阶段根据 props 更新 state,最后先比较 this.props和nextProps后再调用setState()
如果是父组件导致重新渲染,即使 props 没变更也会被调用
componentWillReceiveProps计划在 React V17.0.0 之后废弃掉该生命周期函数会受到
static getDerivedStateFromProps()和getSnapshotBeforeUpdate()的影响而无法使用
class MyComponent extends React.Component {
componentWillReceiveProps(nextProps) {
if (nextProps.value === this.props.value) {
this.setState({
selectedVal: nextProps.value,
});
}
}
// ...
}shouldComponentUpdate(nextProps, nextState)
shouldComponentUpdate()在一个已经挂载的组件接收到新的 props 或 state 时被调用,其返回一个布尔值告诉 React 是否应该进行更新。默认情况下,每一次的状态变更都会进行重新渲染。
当shouldComponentUpdate()的返回false时,UNSAFE_componentWillUpdate(),render()和componentDidUpdate()都不会被调用。
对于React.PureComponent的子类,shouldComponentUpdate()对 props 和 state 进行了一次浅比较。
如果,
React.PureComponent的子类重写了shouldComponentUpdate()React 在开发环境下会有以下警告:Warning: XXXX has a method called shouldComponentUpdate(). shouldComponentUpdate should not be used when extending React.PureComponent. Please extend React.Component if shouldComponentUpdate is used.
class MyComponent extends React.Component {
shouldComponentUpdate(nextProps, nextState) {
for (let key in nextProps) {
if (nextProps[key] === this.props[key]) {
return true;
}
}
for (let key in nextState) {
if (nextState[key] === this.state[key]) {
return true;
}
}
}
// ...
}UNSAFE_componentWillUpdate(nextProps, nextState)
componentWillUpdate()的新名称,在一个已经挂载的组件接收到新的 props 或 state,并且shouldComponentUpdate()返回true时被调用。这是在更新之前最后一次准备的机会。
不要在这个阶段调用
this.setState(),dispatch Redux 的 action 也一样,否则,可能会导致 React 组件在UNSAFE_componentWillUpdate()返回前就进行了一次更新。
componentWillUpdate计划在 React V17.0.0 之后废弃掉该生命周期函数会受到
static getDerivedStateFromProps()和getSnapshotBeforeUpdate()的影响而无法使用
getSnapshotBeforeUpdate(prevProps, prevState)
React V16.3.0 新增的生命周期。在当前已挂载的组件调用 render() 之后调用。该函数的返回值将作为componentDidMount()的第三个参数传递下去。
一旦使用了这个新的生命周期函数,不安全的生命周期函数将不会被调用
class ScrollingList extends React.Component {
listRef = React.createRef();
getSnapshotBeforeUpdate(prevProps, prevState) {
// Are we adding new items to the list?
// Capture the current height of the list so we can adjust scroll later.
if (prevProps.list.length < this.props.list.length) {
return this.listRef.current.scrollHeight;
}
return null;
}
componentDidUpdate(prevProps, prevState, snapshot) {
// If we have a snapshot value, we've just added new items.
// Adjust scroll so these new items don't push the old ones out of view.
if (snapshot !== null) {
this.listRef.current.scrollTop +=
this.listRef.current.scrollHeight - snapshot;
}
}
render() {
return (
<div ref={this.listRef}>{/* ...contents... */}</div>
);
}
}componentDidUpdate(prevProps, prevState, snapshot)
componentDidUpdate()在更新结束后立刻被调用,可以在这个阶段进行 DOM 的操作、网络请求等。
class MyComponent extends React.Component {
_loadData() {}
componentDidUpdate(prevProps, prevState, snapshot) {
if (prevProps.province !== this.props.province) {
this._loadData();
this.amap.setProvince(this.props.province)
}
}
// ...
}componentWillUnmount()
当一个组件即将被卸载和销毁时会立刻调用componentWillUnmount()函数,在这个阶段可以进行取消网络、清空订阅等操作。
class MyComponent extends React.Component {
componentWillUnmount() {
clearInterval(this.intervalKey);
unsubscript(this.subscriptKey);
}
// ...
}最后更新于