生命周期函数,也叫做生命周期钩子,是react为我们提供的,可以在一些特定时间点进行操作的API方法。例如在组件挂载完成后请求后台数据,或是在组件销毁时清除定时器等
生命周期钩子(旧)
旧版本为react v17.0以前使用的版本。简单介绍一下图中的生命周期钩子。
//组件将要挂载的钩子
componentWillMount(){
console.log('Count---componentWillMount');
}
//组件挂载完毕的钩子
componentDidMount(){
console.log('Count---componentDidMount');
}
//组件将要卸载的钩子
componentWillUnmount(){
console.log('Count---componentWillUnmount');
}
//控制组件更新的“阀门”,通过返回的布尔值来判断是否要更新组件
shouldComponentUpdate(){
console.log('Count---shouldComponentUpdate');
return true
}
//组件将要更新的钩子
componentWillUpdate(){
console.log('Count---componentWillUpdate');
}
//组件更新完毕的钩子
componentDidUpdate(){
console.log('Count---componentDidUpdate');
}
//子组件
//组件将要接收新的props的钩子,接收一个参数,为传入的props
componentWillReceiveProps(props){
console.log('B---componentWillReceiveProps',props);
}
如图所示,可以分为三个阶段,生命周期调用顺序如下
- 初始化阶段: 由ReactDOM.render()触发—初次渲染
1. constructor()
2. componentWillMount()
3. render()
4. componentDidMount() =====> 常用
一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息 - 更新阶段: 由组件内部this.setSate()或父组件render触发
1. shouldComponentUpdate()
2. componentWillUpdate()
3. render() =====> 必须使用的一个
4. componentDidUpdate() - 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
1. componentWillUnmount() =====> 常用
一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息
生命周期钩子(新17.0)
在react v17.0版本以上,官方建议使用新版生命周期钩子。
如图所示,相比于旧版本的生命周期,移除了三个will的钩子: componentWillMount();componentWillUpdate();componentWillReceiveProps();
并不是删除了,依然可以在代码中使用,但是会提示添加UNSAFE_前缀。提醒开发者将来可能会移除这些钩子。
添加了两个新的钩子:getDerivedStateFromProps();getSnapshotBeforeUpdate();
新生命周期钩子调用顺序:
- 初始化阶段: 由ReactDOM.render()触发—初次渲染
1. constructor()
2. getDerivedStateFromProps
3. render()
4. componentDidMount() =====> 常用
一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息 - 更新阶段: 由组件内部this.setSate()或父组件重新render触发
1. getDerivedStateFromProps
2. shouldComponentUpdate()
3. render()
4. getSnapshotBeforeUpdate
5. componentDidUpdate() - 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
1. componentWillUnmount() =====> 常用
一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息
getDerivedStateFromProps
这个钩子翻译过来的意思就是从props中获取state,这个函数会在每次render之前被调用,即使你的props没有任何变化,而是父组件发生变化,导致子组件发生了re-render,这个生命周期函数依然会被调用。官方推荐使用在当state值在任何时候都取决于props时。
作为componentWillReceiveProps
的替代钩子,用法有很大区别,getDerivedStateFromProps
是一个静态函数,需要添加static前缀,并且无法通过this来获取组件实例。
getDerivedStateFromProps
需要返回一个状态对象(state)或者null
//接收两个参数,一个是传入的props,另一个是当前组件的state
static getDerivedStateFromProps(props, state) {
const {type} = props;
// 当传入的type发生变化的时候,更新state
if (type !== state.type) {
return {
type,
};
}
// 否则,对于state不进行任何操作
return null;
}
官方文档说明,使用这个钩子可能会导致代码冗余,且难以维护,了解即可。
getSnapshotBeforeUpdate
getSnapshotBeforeUpdate(prevProps, prevState)
方法按翻译语义化理解就是“获得更新之前的快照”,也就是可以在组件更新之后保存更新前的状态。可以接收两个参数,一个是更新前的props,第二个是更新前的state。该钩子始终与componentDidUpdate()
方法一起使用,返回值将传递给componentDidUpdate()方法的第三个参数。
举个例子,模拟一个弹幕自动刷新的效果,旧的弹幕在下,新的弹幕在上,当超出弹幕框高度后旧的会被挤出可视区域,导致可视区滚动。现在需要实现,当弹幕超出高度时,继续在弹幕框中刷新,但是可视区域不会滚动。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<style>
.list{
width: 200px;
height: 150px;
background-color: skyblue;
overflow: auto;
}
.news{
height: 30px;
}
</style>
</head>
<body>
<!-- 准备好一个“容器” -->
<div id="test"></div>
<!-- 引入react核心库 -->
<script type="text/javascript" src="../js/17.0.1/react.development.js"></script>
<!-- 引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/17.0.1/react-dom.development.js"></script>
<!-- 引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/17.0.1/babel.min.js"></script>
<script type="text/babel">
class NewsList extends React.Component{
state = {newsArr:[]}
componentDidMount(){
setInterval(() => {
//获取原状态
const {newsArr} = this.state
//模拟一条弹幕
const news = '弹幕'+ (newsArr.length+1)
//更新状态
this.setState({newsArr:[news,...newsArr]})
}, 1000);
}
getSnapshotBeforeUpdate(){
//保存了更新前弹幕框的高度
return this.refs.list.scrollHeight
}
componentDidUpdate(preProps,preState,height){
//新的弹幕插入,组件更新,计算弹幕框的滚动条距离顶部的高度=之前滚动条距离顶部的高度+(当前弹幕框真实高度-更新前弹幕框真实高度)
this.refs.list.scrollTop += this.refs.list.scrollHeight - height
}
render(){
return(
<div className="list" ref="list">
{
this.state.newsArr.map((n,index)=>{
return <div key={index} className="news">{n}</div>
})
}
</div>
)
}
}
ReactDOM.render(<NewsList/>,document.getElementById('test'))
</script>
</body>
</html>