「回顾2022,展望2023,我正在参与2022年终总结征文大赛活动」
什么是生命周期
组件从 被创建 到 被销毁 的过程称为组件的生命周期。
React生命周期的三个阶段
React的生命周期分为三个阶段:挂载期(也叫实例化期)、更新期(也叫存在期)、卸载期(也叫销毁期)。在每个周期中React都提供了一些钩子函数。
生命周期的描述如下:
挂载期:一个组件实例初次被创建的过程。
更新期:组件在创建后再次渲染的过程。
卸载期:组件在使用完后被销毁的过程。
生命周期方法
常见方法图
完整方法图
挂载阶段
- constructor: 构造函数,最先被执行,我们通常在构造函数里初始化
state
对象或者给自定义方法绑定this
- getDerivedStateFromProps:
static getDerivedStateFromProps(nextProps, prevState)
,这是个静态方法,当我们接收到新的属性想去修改state
,可以使用getDerivedStateFromProps
- render:
render
函数是纯函数,只返回需要渲染的东西,不应该包含其它的业务逻辑,可以返回原生的DOM、React组件、Fragment、Portals、字符串和数字、Boolean和null等内容 - componentDidMount: 组件装载之后调用,此时可以获取到DOM节点并操作,比如对canvas,svg的操作,服务器请求,订阅都可以写在这个里面,但是记得在
componentWillUnmount
中取消订阅。
更新阶段
- getDerivedStateFromProps: 此方法在更新个挂载阶段都可能会调用
- shouldComponentUpdate:
shouldComponentUpdate(nextProps, nextState)
,有两个参数nextProps
和nextState
,表示新的属性和变化之后的state
,返回一个布尔值,true
表示会触发重新渲染,false
表示不会触发重新渲染,默认返回true
,我们通常利用此生命周期来优化React程序性能 - render: 更新阶段也会触发此生命周期
- getSnapshotBeforeUpdate:
getSnapshotBeforeUpdate(prevProps, prevState)
,这个方法在render
之后,componentDidUpdate
之前调用,有两个参数prevProps
和prevState
,表示之前的属性和之前的state
,这个函数有一个返回值,会作为第三个参数传给componentDidUpdate
,如果你不想要返回值,可以返回null,此生命周期必须与componentDidUpdate
搭配使用 - componentDidUpdate:
componentDidUpdate(prevProps, prevState, snapshot)
,该方法在getSnapshotBeforeUpdate
方法之后被调用,有三个参数prevProps
,prevState
,snapshot
,表示之前的props,之前的state,和snapshot。第三个参数是getSnapshotBeforeUpdate
返回的,如果触发某些回调函数时需要用到 DOM 元素的状态,则将对比或计算的过程迁移至getSnapshotBeforeUpdate
,然后在componentDidUpdate
中统一触发回调或更新状态。
卸载阶段
- componentWillUnmount: 当组件被卸载或者销毁了就会调用,我们可以在这个函数里去清除一些定时器,取消网络请求,清理无效的DOM元素等垃圾清理工作。
代码演示
<!-- 生命周期 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://unpkg.com/react@17.0.2/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@17.0.2/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<title>Document</title>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
class Count extends React.Component {
constructor(props) {
console.log('constructor');
super(props);
this.state = {
count: 0
}
}
add = () => {
this.setState({
count: this.state.count + 1
})
}
death = () => {
ReactDOM.unmountComponentAtNode(document.getElementById('root'))
// React提供的方法 把该容器root的子节点全部移除
}
force = () => {
this.forceUpdate()
}
// 得到一个额外的状态
static getDerivedStateFromProps(props, state) {
// 将父组件传过来的props和自己组件的state进行合并
console.log(' getDerivedStateFromProps', props, state);
return null
}
// 组件挂载完毕
componentDidMount() {
console.log('componentDidMount');
}
// 控制组件更新的'阀门'
shouldComponentUpdate() { // 人为的控制组件是否允许更新
console.log('shouldComponentUpdate');
return true; // 为false时,不会执行后面的render(),组件不更新
}
// 更新之前获取快照 快照的意思就是相当于在某个时间点截图,截图里的数据在该时间点后变更了,
//但是因为你快照过,就相当于证明你曾经有过这些数据
getSnapshotBeforeUpdate() {
console.log('getSnapshotBeforeUpdate');
return 'hello' // return的值传给 componentDidUpdate 作为参数
}
// 组件更新完毕
componentDidUpdate(preProps, preState, snapshotValue) {
console.log('componentDidUpdate', preProps, preState, snapshotValue);
}
// 组件卸载 就是这个组件跳到别的组件,这个组件就会被卸载掉
componentWillUnmount() {
console.log('componentWillUnmount');
}
render() {
console.log('render');
const { count } = this.state
return (
<div>
<h2>当前求和为:{count}</h2>
<button onClick={this.add}>点我+1</button>
<button onClick={this.death}>卸载组件</button>
<button onClick={this.force}>不更改任何状态数据,强制更新一下</button>
</div>
)
}
}
ReactDOM.render(<Count count={100} />, document.getElementById('root'))
</script>
</body>
</html>