一、生命周期是什么
React 组件的生命周期是一种钩子函数,其实也可以理解为是一种回调函数,是 React 组件在创建更新卸载的整个过程中对外暴露出的方法,然后 React 组件会根据方法的返回值来决定内部怎么运作。比如 shouldComponentUpdate 的返回值是 false,那么即便是调用了 this.setState() 方法,也不会重新渲染页面;反之,如果是 true,则会重新渲染页面,也就是重新执行一遍 render() 方法。
二、生命周期有哪些
React 组件的生命周期分为三个阶段,一共有10个生命周期函数:
1. 初始化阶段
- getDefaultProps
- getInitialState
- componentWillMount
- render
- componentDidMount
2. 更新阶段
- componentWillReceiveProps
- shouldComponentUpdate
- componentWillUpdate
- render
- componentDidUpdate
3. 卸载阶段
- componentWillUnmount
三、生命周期详解
下面会讲解一下每个生命周期的用法,并附带案例。
1. 初始化阶段
- getDefaultProps:初始化 props,可以用 defaultProps 代替。
- getInitialState:初始化 state,一般写在 this.state = {} 中。
这两个生命周期函数都是定义在 createClass 方法中。用法如下:
var App = React.createClass({
getDefaultProps(){
return{
title:'首页'
}
},
getInitialState(){
return{
data:'数据'
}
},
render(){
return <div>{this.props.title}{this.state.data}</div>
}
})
ReactDOM.render(<App/>, document.getElementById('example'));
如果用 defaultProps 和 this.state 代替, 用法如下:
class App extends React.Component {
constructor(props){
super(props);
this.state = {
data:'数据'
}
}
render() {
return (
<div>
<div>{this.props.title}{this.state.data}</div>
</div>
)
}
};
App.defaultProps = {
title:'首页'
};
ReactDOM.render(<App/>, document.getElementById('example'));
- componentWillMount:准备创建虚拟 DOM。
- render:虚拟组件渲染,挂载。
- componentDidMount:虚拟组件已经挂载完成,可在此阶段更新 state,或者调用接口,处理监听事件。
class App extends React.Component {
constructor(props){
super(props);
this.state = {
title:'我是主页'
}
}
componentWillMount(){
//如果在 constructor 构造函数中我想重写 state,就可以在这里进行,
//但仅仅只是改变 state,不会渲染页面
this.state = {
title:'不,我是首页'
}
}
componentDidMount(){
//在这里,我可以调取数据接口,
//执行 this.setState 改变 state,并且重新渲染页面
}
render() {
return <div>最终的title为:{this.state.title}</div>
}
};
ReactDOM.render(<App/>, document.getElementById('example'));
2. 更新阶段
- componentWillReceiveProps:父组件更新引发子组件更新时调用。
- shouldComponentUpdate:布尔值,是否更新组件,用来做性能优化。
- componentWillUpdate:组件刚开始更新的时候,还未重新渲染 DOM 时触发。
- render:根据更新的 state 和 props 重新渲染页面。
- componentDidUpdate:组件完成更新,DOM 渲染完成。
class App extends React.Component {
constructor(props){
super(props);
this.state = {
isRender:true,
toSonText:'给子组件的props为1'
};
}
click(){
this.setState({
toSonText:'给子组件的props为2'
})
}
render() {
return <div onClick={()=>this.click()}><Index message = {this.state.toSonText}/>点击我改变传给子组件的props</div>
}
};
class Index extends React.Component {
constructor(props){
super(props);
this.state = {
title:'我是主页'
}
}
componentWillReceiveProps(nextProps, nextContext){
//当父组件更新时,我就会触发,并拿到最新的 props
console.log(nextProps.message)
}
componentWillUpdate(){
//state 更新时,我还可以在挂载前改变 state,但是不会重新渲染页面
this.state.title = '不,我是首页'
}
componentDidUpdate(){
//state 更新完成,我可以改变 state 并且渲染页面
//可以在这里调取数据接口,执行 this.setState 改变 state 并渲染页面
}
render() {
return <div><div>父组件传过来的 message 为:{this.props.message}</div><div>最终的title为:{this.state.title}</div></div>
}
};
ReactDOM.render(<App/>, document.getElementById('example'));
3. 卸载阶段
- componentWillUnmount:组件卸载时触发。在这个阶段可以消除一些定时器或事件。
如下代码所示,点击父组件卸载掉子组件,并清掉定时器。
class App extends React.Component {
constructor(props){
super(props);
this.state = {
isRender:true
};
}
click(){
this.setState({
isRender:false
})
}
render() {
return <div onClick={()=>this.click()}>{this.state.isRender?<Index/>:null}<div>点击</div></div>
}
};
class Index extends React.Component {
constructor(props){
super(props);
this.state = {
count:0
}
}
componentDidMount(){
this.timer = setInterval(()=>{
this.setState({
count:++this.state.count
})
},1000)
}
componentWillUnmount(){
clearInterval(this.timer);
}
render() {
return <div>{this.state.count}</div>
}
};
ReactDOM.render(<App/>, document.getElementById('example'));
如果不清掉定时器,定时器仍在执行,但是组件已不再,所以会一直报错如下: