javascript

彻底理解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")
)

小结一下:

未完,等续

上一篇下一篇

猜你喜欢

热点阅读