彻底理解React组件的生命周期(一)
2018-09-07 本文已影响49人
张培跃
React组件的生命周期,主要分为挂载、更新以及移除阶段的生命周期。所谓挂载指的是组件从初始化到渲染到页面的过程。卸载指的是组件生成的DOM元素从页面中删除的过程。更新指的是组件更新的过程。那么在这些过程当中它都经历了些什么呢?
首先来一段代码:
ReactDOM.render(
<Book/>
document.querySelector("#wrap")
)
其实以上代码在经过React.js的编译后会变成这个样子:
ReactDOM.render(
// <Book/>,
React.createElement(Book),
document.querySelector("#wrap")
)
也就是说将Book传给了React.createElement函数,又将该函数的结果返回给了ReactDOM.rende。最后将组件挂载到了id为wrap的元素中!我们也可以大胆的猜测一下在这个过程中它都做了些什么事:
// React.createElement 中实例化一个 Book
const book = new Book(props, children)
// React.createElement 中调用 book.render 方法渲染组件的内容
const bookJsxObject = book.render()
// ReactDOM 用渲染后的 JavaScript 对象来来构建真正的 DOM 元素
const bookDOM = createDOMFromObject(bookJsxObject)
// ReactDOM 把 DOM 元素塞到页面上
document.querySelector("#wrap").innerHTML=bookDOM;
以上代码也可以简单理解为:
// 实例化组件,也就是构造DOM元素
constructor();
// 将构造的元素插入到指定的页面元素中
render();
不过在挂载的过程当中,其实还有两个方法,分别为componentWillMount 和 componentDidMount。
// 实例化组件,也就是构造DOM元素
constructor();
// 当DOM元素载入之前调用
componentWillMount();
// 将构造的元素插入到指定的页面元素中
render();
// 当DOM元素载入页面之后调用
componentDidMount();
componentWillMount方法在组件挂载到页面之前调用。而componentDidMount方法是在挂载到页面以后调用。我们也可以将这两个方法放到组件内部:
class Book extends React.Component{
constructor(){
super();
console.log("执行constructor");
}
componentWillMount(){
console.log("执行componentWillmount");
}
componentDidMount(){
console.log("执行componentDidMount");
}
render(){
console.log("执行render");
return (
<div>大家好,我叫张培跃</div>
)
}
}
ReactDOM.render(
<Book/>,
document.querySelector("#wrap")
)
通过以上示例的输出结果,我们也可以看到方法的执行顺序:
->执行constructor
->执行componentWillmount
->执行render
->执行componentDidMount
componentWillmount在render之前,componentDidMount在render之后
接下来咱们再来思考一个问题,我们既然可以将组件挂载到页面中,自然也可以将组件在页面中进行卸载。而当组件卸载之前会调用组件的componentWillUnmount方法:
// 实例化组件,也就是构造DOM元素
constructor();
// 当DOM元素载入之前调用
componentWillMount();
// 将构造的元素插入到指定的页面元素中
render();
// 当DOM元素载入页面之后调用
componentDidMount();
// 当从页面中卸载时会调用
componentWillUnmount()
接下来,我们再来定义一个组件,让该组件控制对Book组件的挂载与卸载:
class My extends React.Component{
constructor(){
super();
this.state={
isShow:true
};
this.changeIsShow=this.changeIsShow.bind(this);
}
changeIsShow(){
this.setState({
isShow:!this.state.isShow
})
}
render(){
return (
<div>
<input type="button" value="点我啊"
onClick={this.changeIsShow}/>
{/*根据isShow来对Book进行挂载与卸载*/}
{this.state.isShow?<Book />:null}
</div>
)
}
}
ReactDOM.render(
<My/>,
document.querySelector("#wrap")
)
然后在在Book组件中增加componentWillUnmount方法:
class Book extends React.Component{
constructor(){
super();
console.log("执行constructor");
}
componentWillMount(){
console.log("执行componentWillmount");
}
componentDidMount(){
console.log("执行componentDidMount");
}
componentWillUnmount(){
console.log("执行componentWillUnmount");
}
render(){
console.log("执行render");
return (
<div>大家好,我叫张培跃</div>
)
}
}
当点击按钮时控制台会输出最后一行,说明componentWillUnmount方法在被卸载时调用了:
->执行constructor
->执行componentWillmount
->执行render
->执行componentDidMount
完整示例代码:
class Book extends React.Component{
constructor(){
super();
console.log("执行constructor");
}
componentWillMount(){
console.log("执行componentWillmount");
}
componentDidMount(){
console.log("执行componentDidMount");
}
componentWillUnmount(){
console.log("执行componentWillUnmount");
}
render(){
console.log("执行render");
return (
<div>大家好,我叫张培跃</div>
)
}
}
class My extends React.Component{
constructor(){
super();
this.state={
isShow:true
};
this.changeIsShow=this.changeIsShow.bind(this);
}
changeIsShow(){
this.setState({
isShow:!this.state.isShow
})
}
render(){
return (
<div>
<input type="button" value="点我啊"
onClick={this.changeIsShow}/>
{/*根据isShow来对Book进行挂载与卸载*/}
{this.state.isShow?<Book />:null}
</div>
)
}
}
ReactDOM.render(
<My/>,
document.querySelector("#wrap")
)
到目前为止,咱们已经见证了组件从出生到死亡的一个过程!接下来我们一起通过一个计数器的实例来了解这些函数的作用!
现在我们要完成一个倒计时的小应用,如下:
首先通过constructor进行初始化:
class AddOne extends React.Component{
constructor(){
super();
//设置初始值
this.state={
num:0,
timer:null
}
}
componentWillMount(){
// 组件挂载时添加计数器
this.timer=setInterval(()=>{
this.setState({
num:this.state.num+1
})
},1000)
}
componentWillUnmount(){
// 组件卸载时移除计数器
clearInterval(this.timer);
}
render(){
return (
<div>
<h1>{this.state.num}</h1>
</div>
)
}
}
class Start extends React.Component{
constructor(){
super();
this.state={
isShow:false
};
this.changeIsShow=this.changeIsShow.bind(this);
}
changeIsShow(){
this.setState({
isShow:!this.state.isShow
})
}
render(){
return (
<div>
<input type="button" value={this.state.isShow?"结束":"开始计时"} onClick={this.changeIsShow}/>
{this.state.isShow?<AddOne />:null}
</div>
);
}
}
ReactDOM.render(
<Start/>,
document.querySelector("#wrap")
)
小结一下:
- componentWillMount:在组件调用 render 方法之前调用。
- componentDidMount:是 DOM 元素已经插入页面后调用。
- componentWillUnmount:组件对应的 DOM 元素从页面中卸载之前调用。
未完,等续