目录
1 生命周期与钩子函数
2 创建时
3 更新时
3.1 执行顺序
3.2 触发条件
3.3 componentDidUpdate()
4 卸载时
1 生命周期与钩子函数
类组件从 被挂载到页面中运行,到组件不用时卸载 之间是组件的生命周期
- 只有类组件才有生命周期
生命周期的每个阶段可以使用一些方法,这些方法称为钩子函数(很像中间件)
生命周期有三个阶段,依次是 创建时,更新时,卸载时。在下图中 constructor,render,componentDidMount,componentDidUpdate.componentWillUnmount 是钩子函数
上面这张图只是常用的钩子函数,还有很多不常用钩子函数可以去看文档
2 创建时
在创建时会依次执行 constructor,render,componentDidMount
我们测试一下这三个钩子函数的执行顺序
这三个函数的触发机制是这样的
render()每一次渲染都会触发,所以在更新的时候也会触发。由于setState()会改变组件状态导致组件渲染,组件渲染会执行render(),所以一般不在render()中调用setState()
如果实在要调用,需要给setState()一个条件,这样就不会陷入死循环,它只会提示一个warning
只有在渲染元素后才能用 document.querySelector()这种方法获取到元素,所以我们一般在componentDidMount进行渲染后的操作
3 更新时
更新时会依次触发 render()与 componentDidUpdate()
componentDidUpdate()在更新后触发,所以在componentDidUpdate()中使用setState()也要放在一个条件中使用,在componentDidUpdate()条件使用setState()不会出现warning
3.1 执行顺序
打开后会先执行父子组件的两个render(),但并不执行componentDidUpdate()
点击按钮后会再次执行render(),子组件先更新完成,所以子组件先执行componentDidUpdate
3.2 触发条件
有三种情况会触发更新
- New props 接收到外部新的数据
- setState() 自身设置了新的数据
- forceUpdate() 调用forceUpdate()时会强制更新一次
在上面的例子中,通过props更新了子组件,通过setState()更新了父组件
使用forceUpdate()也可以更新组件
点击按钮后可以触发render()与componentDidUpdate()
3.3 componentDidUpdate()
componentDidUpdate()可以使用参数prevProps,prevProps表示 本次的上一次更新 的props
我们看一下prevProps顺便验证一下在componentDidUpdate()中条件使用setState(),如果上一次与这一次的props不一致就重新渲染一遍
由于我在子组件的componentDidUpdate()加入了setState(),所以子组件的componentDidUpdate()执行了两次
父组件的componentDidUpdate()没有加入setState(),所以只执行了一次
4 卸载时
测试代码是这样的
class Child extends React.Component {
componentWillUnmount() {
console.log('子组件的componentWillUnmount')
}
render() {
return (
<div>count是{this.props.count}</div>
)
}
}
class Father extends React.Component {
constructor(props) {
super(props)
this.state = {
count:0
}
}
add_one = ()=>{
this.setState({count:this.state.count + 1})
}
p_or_Child = ()=>{
if (this.state.count >=1) {
return <p>不再渲染Child组件</p>
}
else {
return <Child count={this.state.count}></Child>
}
}
componentWillUnmount() {
console.log('父组件的componentWillUnmount')
}
render() {
return (
<div>
{this.p_or_Child()}
<button onClick={this.add_one}>+1</button>
</div>
)
}
}
ReactDOM.createRoot(document.querySelector('div')).render(<Father></Father>)
点击一次后用p标签代替组件Child,这样就会触发Child卸载
定义父组件与子组件的 componentWillUnmount()
点击之前是这样的
点击之后只触发了子组件的componentWillUnmount()
通常我们会在componentWillUnmount()中清楚组件遗留的内容,比如使用setInterval()定义的定时器,当组件消失后 使用setInterval()定义的定时器 并不会随组件的消失而消失,
点之前定时器在运行
点之后定时器还在运行
所以我们需要在componentWillUnmount()进行手动清除
这样点击完毕之后定时器就不再运行了