ReactJS - 组件生命周期



在 React 中,组件的生命周期表示组件在其存在期间的不同阶段。React 提供了回调函数,用于在 React 生命周期的每个阶段附加功能。在本章中,让我们学习 React 组件的生命周期(以及相关的 API)。

生命周期 API

每个 React 组件都有三个不同的阶段。

  • 挂载 − 挂载表示React组件在给定DOM节点中的渲染。
  • 更新 − 更新表示在状态更改/更新期间在给定的 DOM 节点中重新渲染 React 组件。
  • 卸载 − 卸载代表删除 React 组件。

React 提供了一组生命周期事件(或回调 API)来附加功能,这些功能将在组件的各个阶段执行。生命周期的可视化以及生命周期事件 (API) 的调用顺序,如下所示。

Life Cycle

constructor() - 在React组件的初始构建阶段调用。用于设置组件的初始状态和属性。

render() - 在组件构造完成后调用。它在虚拟 DOM 实例中呈现组件。这被指定为在 DOM 树中挂载组件。

componentDidMount() − 在组件在 DOM 树中初始挂载后调用。它是调用 API 端点和执行网络请求的好地方。在我们的时钟组件中,可以在此处设置 setInterval 函数来更新每秒的状态(当前日期和时间)。


componentDidMount() {	
	 	this.timeFn = setInterval( () => this.setTime(), 1000);	
}

componentDidUpdate() − 类似于 ComponentDidMount(),但在更新阶段调用。在此阶段可以执行网络请求,但前提是组件的当前属性和以前的属性存在差异。

API的签名如下 -

componentDidUpdate(prevProps, prevState, snapshot)
  • prevProps - 组件的先前属性。
  • prevState − 组件的先前状态。
  • snapshot - 当前呈现的内容。

componentWillUnmount() − 在组件从 DOM 中卸载后调用。这是清理对象的好地方。在我们的时钟示例中,我们可以在此阶段停止更新日期和时间。


componentDidMount() {	
	 	this.timeFn = setInterval( () => this.setTime(), 1000);	
}

shouldComponentUpdate() − 在更新阶段调用。用于指定组件是否应更新。如果返回 false,则不会发生更新。

签名如下 -

shouldComponentUpdate(nextProps, nextState)
  • nextProps - 组件即将推出的属性
  • nextState − 组件即将出现的状态

getDerivedStateFromProps - 在初始和更新阶段以及render()方法之前调用。它返回新的状态对象。在属性更改导致状态更改的情况下,很少使用它。它主要用于动画上下文中,其中需要组件的各种状态来执行流畅的动画。

API的签名如下 -

static getDerivedStateFromProps(props, state)
  • props - 组件的当前属性
  • state - 组件的当前状态

这是一个静态方法,无权访问此对象。

getSnapshotBeforeUpdate − 在将渲染内容提交到 DOM 树之前调用。它主要用于获取有关新内容的一些信息。此方法返回的数据将传递给 ComponentDidUpdate() 方法。例如,它用于在新生成的内容中保持用户的滚动位置。它返回用户的滚动位置。componentDidUpdate() 使用此滚动位置来设置实际 DOM 中输出的滚动位置。

API的签名如下:

getSnapshotBeforeUpdate(prevProps, prevState)
  • prevProps - 组件的先前属性。
  • prevState − 组件的先前状态。

生命周期API工作示例

让我们在 react-clock-app 应用程序中使用生命周期 api。

第 1 步 - 在您最喜欢的编辑器中打开react-clock-hook-app。

打开 src/components/Clock.js 文件并开始编辑。

第 2 步 - 从构造函数中删除 setInterval() 方法。


constructor(props) {	
	 	super(props);	
	 	this.state = {	
	 	 	 date: new Date()	
	 	}	
}

第 3 步 - 添加 componentDidMount() 方法并调用 setInterval() 以每秒更新日期和时间。此外,存储引用以在以后停止更新日期和时间。


componentDidMount() {	
	 	this.setTimeRef = setInterval(() => this.setTime(), 1000);	
}

添加 componentWillUnmount() 方法并调用 clearInterval() 以停止日期和时间更新调用。


componentWillUnmount() {	
	 	clearInterval(this.setTimeRef)	
}

现在,我们已经更新了 Clock 组件,下面给出了该组件的完整源代码 -


import React from 'react';

class Clock extends React.Component {
	 	constructor(props) {
	 	 	 super(props);
	 	 	 this.state = {
	 	 	 	 	date: new Date()
	 	 	 } 	 	 	
	 	}
	 	componentDidMount() {
	 	 	 this.setTimeRef = setInterval(() => this.setTime(), 1000);	
	 	}
	 	componentWillUnmount() {
	 	 	 clearInterval(this.setTimeRef)
	 	}
	 	setTime() {
	 	 	 this.setState((state, props) => {
	 	 	 	 	console.log(state.date);
	 	 	 	 	return {
	 	 	 	 	 	 date: new Date()
	 	 	 	 	}
	 	 	 })
	 	}
	 	render() {
	 	 	 return (
	 	 	 	 	<div>
	 	 	 	 	 	 <p>The current time is {this.state.date.toString()}</p>
	 	 	 	 	</div>
	 	 	 );
	 	}
}
export default Clock;

接下来,打开 index.js 并使用 setTimeout 在 5 秒后从 DOM 中删除时钟。


import React from 'react';
import ReactDOM from 'react-dom';
import Clock from './components/Clock';

ReactDOM.render(
	 	<React.StrictMode>
	 	 	 <Clock />
	 	</React.StrictMode>,
	 	document.getElementById('root')
);
setTimeout(() => {
	 	ReactDOM.render(
	 	 	 <React.StrictMode>
	 	 	 	 	<div><p>Clock is removed from the DOM.</p></div>
	 	 	 </React.StrictMode>,
	 	 	 document.getElementById('root')
	 	);
}, 5000);

使用 npm 命令为应用程序提供服务。

npm start

打开浏览器,在地址栏中输入 http://localhost:3000,然后按回车键。

时钟将显示 5 秒钟,然后从 DOM 中删除。通过检查控制台日志,我们可以发现清理代码已正确执行。

接口 DOM

费用管理器应用中的生命周期 API

让我们在费用管理器中添加生命周期 api,并在调用 api 时记录它。这将提供有关组件生命周期的见解。

第 1 步 - 在您最喜欢的编辑器中打开费用管理器应用程序。

接下来,使用以下方法更新 ExpenseEntryItemList 组件。


componentDidMount() {
	 	console.log("ExpenseEntryItemList :: Initialize :: componentDidMount :: Component mounted");
}
shouldComponentUpdate(nextProps, nextState) {
	 	console.log("ExpenseEntryItemList :: Update :: shouldComponentUpdate invoked :: Before update");
	 	return true;
}
static getDerivedStateFromProps(props, state) {
	 	console.log("ExpenseEntryItemList :: Initialize / Update :: getDerivedStateFromProps :: Before update");
	 	return null;
}
getSnapshotBeforeUpdate(prevProps, prevState) {
	 	console.log("ExpenseEntryItemList :: Update :: getSnapshotBeforeUpdate :: Before update");
	 	return null;
}
componentDidUpdate(prevProps, prevState, snapshot) {
	 	console.log("ExpenseEntryItemList :: Update :: componentDidUpdate :: Component updated");
}
componentWillUnmount() {
	 	console.log("ExpenseEntryItemList :: Remove :: componentWillUnmount :: Component unmounted");
}

第 2 步 - 使用 npm 命令提供应用程序。

npm start

打开浏览器,在地址栏中输入 http://localhost:3000,然后按回车键。

接下来,检查控制台日志。它将在初始化阶段显示生命周期 api,如下所示。

ExpenseEntryItemList :: Initialize / Update :: getDerivedStateFromProps :: Before update
ExpenseEntryItemList :: Initialize :: componentDidMount :: Component mounted

删除项目,然后检查控制台日志。它将在更新阶段显示生命周期 API,如下所示。

ExpenseEntryItemList :: Initialize / Update :: getDerivedStateFromProps :: Before update
ExpenseEntryItemList.js:109 ExpenseEntryItemList :: Update :: shouldComponentUpdate invoked :: Before update
ExpenseEntryItemList.js:121 ExpenseEntryItemList :: Update :: getSnapshotBeforeUpdate :: Before update
ExpenseEntryItemList.js:127 ExpenseEntryItemList :: Update :: componentDidUpdate :: Component updated

最后,删除所有生命周期 api,因为它可能会阻碍应用程序性能。只有当情况需要时,才应使用生命周期 API。