React组件生命周期介绍
一、前言
在组件整个生命周期中,随着组件的props
或者state
发生改变,其DOM
表现也会发生相应的变化。
一个组件就是一个状态机,对于特定地输入,它总返回一致的输出。
二、生命周期图例
一个React
组件的生命周期分为三个部分:实例化、存在期和销毁时。
React
应用中,组件加载顺序及生命周期如下图所示:
2.1 constructor( )
constructor
是ES6
对类的默认方法,通过 new
命令生成对象实例时自动调用该方法。并且,该方法是类中必须有的,如果没有显示定义,则会默认添加空的constructor( )
方法。当存在constructor
的时候⚠️必须手动调用super
方法。 在constructor
中如果要访问this.props
需要传入props
,示例如下:
class MyClass extends React.component{
constructor(props){
super(props); // 声明constructor时必须调用super方法
console.log(this.props); // 可以正常访问this.props
}
}
constructor
常用来初始化state
class MyClass extends React.Component {
constructor(props){
super(props);
this.state = {
list: this.props.List
};
}
}
2.2 componentWillMount()
在组件挂载之前调用且全局只调用一次。如果在这个钩子里可以setState
,render
后可以看到更新后的state
,不会触发重复渲染。该生命周期可以发起异步请求,并setState
。(React v16.3
后废弃该生命周期,可以在constructor
中完成设置state
)
2.3 render()
render
是一个React
组件必须定义的生命周期,用来渲染dom
。⚠️不要在render
里面修改state
,会触发死循环导致栈溢出。render
必须返回reactDom。
render() {
const {nodeResultData: {res} = {}} = this.props;
if (isEmpty(res)) return noDataInfo;
const nodeResult = this.getNodeResult(res);
return (
<div className="workspace-dialog-result">
{nodeResult}
</div>
);
2.4 componentDidMount()
在组件挂载完成后调用,且全局只调用一次。可以在这里使用refs
,获取真实dom元素。该钩子内也可以发起异步请求,并在异步请求中可以进行setState
。
componentDidMount() {
axios.get('/auth/getTemplate').then(res => {
const {TemplateList = []} = res;
this.setState({TemplateList});
});
}
2.5 componentWillReceiveProps (nextProps )
props
发生变化以及父组件重新渲染时都会触发该生命周期,在该钩子内可以通过参数nextProps
获取变化后的props
参数,通过this.props
访问之前的props
。该生命周期内可以进行setState
。(React v16.3
后废弃该生命周期,可以用新的周期 static getDerivedStateFromProps
代替)
2.6 shouldComponentUpdate(nextProps, nextState)
用于判断是否重新渲染,组件挂载之后,每次调用setState
后都会调用shouldComponentUpdate
判断是否需要重新渲染组件。默认返回true,需要重新render
。返回false
则不触发渲染。在比较复杂的应用里,有一些数据的改变并不影响界面展示,可以在这里做判断,优化渲染效率。
2.7 componentWillUpdate(nextProps, nextState)
shouldComponentUpdate
返回true或者调用forceUpdate
之后,componentWillUpdate
会被调用。不能在该钩子中setState
,会触发重复循环。(React v16.3
后废弃该生命周期,可以用新的周期 getSnapshotBeforeUpdate
)
2.8 componentDidUpdate()
完成组件渲染,除了首次render
之后调用componentDidMount
,其它render
结束之后都是调用componentDidUpdate
。该钩子内setState
有可能会触发重复渲染,需要自行判断,否则会进入死循环。
componentDidUpdate() {
if(condition) {
this.setState({..}) // 设置state
} else {
// 不再设置state
}
}
2.9 componentWillUnmount()
组件被卸载的时候调用。一般在componentDidMount
里面注册的事件需要在这里删除。
三、Demo
/* 父组件 */
import React, { Component } from 'react';
import Header from './components/Header'
import Footer from './components/Footer'
import BodyIndex from './components/BodyIndex'
class App extends Component {
componentWillMount() {
console.log('App-页面即将加载')
}
componentDidMount() {
console.log('App-页面加载完成')
}
render() {
return (
<div className="App">
<Header />
<BodyIndex />
<Footer />
</div>
);
}
}
export default App;
Header组件,Footer组件、BodyIndex组件同样是在componentWillMount
和componentDidMount
生命周期里调用console.log(),控制台打印信息如下:
/* console.log()内容和顺序如下 */
App-页面即将加载
Header-页面即将加载
body-页面即将加载
Footer-页面即将加载
Header-页面加载完成
body-页面加载完成
Footer-页面加载完成
App-页面加载完成
四、附:React生命周期官方解析
componentWillMount
在渲染前调用,在客户端也在服务端。componentDidMount
: 在第一次渲染后调用,只在客户端。之后组件已经生成了对应的DOM
结构,可以通过this.getDOMNode()
来进行访问。 如果你想和其他JavaScript
框架一起使用,可以在这个方法中调用setTimeout, setInterval或者发送AJAX请求等操作(防止异步操作阻塞UI)。componentWillReceiveProps
在组件接收到一个新的prop
(更新后)时被调用。这个方法在初始化render
时不会被调用。shouldComponentUpdate
返回一个布尔值。在组件接收到新的props
或者state
时被调用。在初始化时或者使用forceUpdate
时不被调用。 可以在你确认不需要更新组件时使用。componentWillUpdate
在组件接收到新的props
或者state
但还没有render时被调用。在初始化时不会被调用。componentDidUpdate
在组件完成更新后立即调用。在初始化时不会被调用。componentWillUnmount
在组件从DOM
中移除的时候立刻被调用。
五、拓展阅读
- 《React 系列》
- 点赞
- 收藏
- 关注作者
评论(0)