Welcome everyone

React组件的生命周期

前端 汪明鑫 736浏览 0评论

首先,附上生命周期这部分的github代码地址

https://github.com/xinyeshuaiqi/ReactLearn/tree/master/7_lifecycle

 

再附上React组件生命周期完整的示意图

 

每一个组件都有关于生命周期的许多方法,我们可以重写这些方法

 

组件生命周期的三个状态

Mounting

下面这些方法将在组件被创建和插入到DOM中时被调用:

Updating

props 或者 state的变化会导致更新,当一个组件被重新渲染时,下面这些方法将被调用:

Unmounting

当一个组件被从DOM中移除时,下面这个方法将会被调用

怎么从DOM中移除一个组件?

ReactDOM.unmountComponentAtNode(document.getElementById('demo')) : 移除demo容器中的组件

 

 

 

上代码来直观感受下组件的生命周期及对应方法的调用:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>组件生命周期</title>
</head>
<body>
<div id="demo"></div>

<script src="../js/react.js"></script>
<script src="../js/react-dom.js"></script>
<script src="../js/babel.min.js"></script>
<script type="text/babel">


    class LifeCycle extends  React.Component{
        constructor(props){
            super(props);

            this.state={
                person:{
                    name:'wmx',
                    age:21
                }
            }

            console.log('constructor被调用  ---->  创建组件实例')
        }

        //组件将要被渲染
        componentWillMount(){
            console.log('componentWillMount被调用  ---->  组件将被渲染')
        }

        //组件已经被渲染
        componentDidMount(){
            console.log('componentDidMount被调用  ---->  组件已经被渲染')
        }

        render(){
            console.log('render被调用  ---->  渲染组件')
            let {person} =this.state;
            return (
                <div>{person.name},{person.age}</div>
            )
        }
    }

    ReactDOM.render(<LifeCycle />,document.getElementById('demo'));

</script>

</body>
</html>

 

constructor、componentWillMount、componentDidMount只调用一次
render什么时候还会调用?

更新状态后 — > 组件更新 — >调用render( )
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>组件生命周期 - 更新</title>
</head>
<body>
<div id="demo"></div>

<script src="../js/react.js"></script>
<script src="../js/react-dom.js"></script>
<script src="../js/babel.min.js"></script>
<script type="text/babel">

    /*
    * 为了便于观察理解,组件的渲染单独放在demo.html
    * demo1.html有组件的更新
    * */

    class LifeCycle extends  React.Component{
        constructor(props){
            super(props);

            this.state={
                person:{
                    name:'xinye',
                    age:21
                }
            }

            console.log('constructor被调用  ---->  创建组件实例')
        }

        //组件将要被渲染
        componentWillMount(){
            console.log('componentWillMount被调用  ---->  组件将被渲染')
            //这里可以发送ajax请求,开启定时器

            /*
            * 为什么ajax请求放在这里?
            * 组件还没有渲染出来,就发送请求,数据来了,页面也刚好渲染出来了
            *
            * 但是如果componentWillMount干的活太重话,render()方法一直还没执行,用户一直等待页面的渲染、
            *
            * 可以根据需求选择在componentWillMount()还是componentDidMount()发送ajax请求
            * */

            //开启定时器   定时器的this是window,因此需要修改this
            setTimeout(function () {
                this.setState({
                    person:{
                        name:'wmx',
                        age:22
                    }
                })
            }.bind(this),5000)  //推迟5秒钟,修改状态
        }

        //组件已经被渲染    用户已经看到界面
        componentDidMount(){
            console.log('componentDidMount被调用  ---->  组件已经被渲染')
        }

        //组件将要更新
        componentWillUpdate(){
            console.log('componentWillUpdate被调用  ---->  组件将要更新')
        }

        //组件已被更新
        componentDidUpdate(){
            console.log('componentDidUpdate被调用  ---->  组件已经更新')
        }

        //组件将被移除
        componentWillUnMount(){
            console.log('componentWillUnMount被调用  ---->  组件将被移除')
        }

        render(){
            console.log('render被调用  ---->  渲染组件')
            let {person} =this.state;
            return (
                <div>{person.name},{person.age}</div>
            )
        }
    }

    ReactDOM.render(<LifeCycle />,document.getElementById('demo'));

</script>

</body>
</html>

 

 

基于上面的代码,我们加一个组件的移除

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>组件生命周期 - 移除</title>
</head>
<body>
<div id="demo"></div>

<script src="../js/react.js"></script>
<script src="../js/react-dom.js"></script>
<script src="../js/babel.min.js"></script>
<script type="text/babel">

    class LifeCycle extends  React.Component{
        constructor(props){
            super(props);

            this.state={
                person:{
                    name:'xinye',
                    age:21
                }
            }

            console.log('constructor被调用  ---->  创建组件实例')
        }

        //组件将要被渲染
        componentWillMount(){
            console.log('componentWillMount被调用  ---->  组件将被渲染')

            setTimeout(function () {
                this.setState({
                    person:{
                        name:'wmx',
                        age:22
                    }
                })
            }.bind(this),3000)  //推迟5秒钟,修改状态

        }

        //组件已经被渲染    用户已经看到界面
        componentDidMount(){
            console.log('componentDidMount被调用  ---->  组件已经被渲染')


            setTimeout(function () {
                //移除组件
                ReactDOM.unmountComponentAtNode(document.getElementById('demo'));   //参数是一个容器
            }.bind(this),5000)  //5秒钟后,移除组件

            //返回一个intervalId 的定时器的标识符塞入实例中
            this.intervalId = setInterval(function () {
                console.log('循环定时器...')
            }.bind(this),1000)
        }

        //组件将要更新
        componentWillUpdate(){
            console.log('componentWillUpdate被调用  ---->  组件将要更新')
        }

        //组件已被更新
        componentDidUpdate(){
            console.log('componentDidUpdate被调用  ---->  组件已经更新')
        }

        //组件将被移除
        componentWillUnmount(){
            console.log('componentWillUnmount被调用  ---->  组件将被移除')

            //在这里做一些收尾工作:关掉一些东西
            //关掉我们在componentDidMount()中的循环定时器
            clearInterval(this.intervalId)
            console.log('循环定时器已关闭...')
        }

        render(){
            console.log('render被调用  ---->  渲染组件')
            let {person} =this.state;
            return (
                <div>{person.name},{person.age}</div>
            )
        }
    }

    ReactDOM.render(<LifeCycle />,document.getElementById('demo'));

</script>

</body>
</html>

还有一个额外的功能就是循环定时器的开启和关闭

div里为空,也证明了组件的移除

 

关于组件生命周期的练习

我们要设置文字的透明度不停地变化

opacity 属性设置元素的不透明级别

从 0.0 (完全透明)到 1.0(完全不透明)。

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>组件生命周期练习</title>
</head>
<body>
<a id="demo" href="http://www.xinyeshuaiqi.cn"></a>

<script src="../js/react.js"></script>
<script src="../js/react-dom.js"></script>
<script src="../js/babel.min.js"></script>
<script type="text/babel">

    //将要展示的效果 : 页面字体的透明度改变
    class ShowSomething extends  React.Component{
        constructor(props){
            super(props);
            this.state={
                opacity:1   //不断修改这个opacity
            }
        }

        componentDidMount(){
            let opacity = this.state.opacity;
            setInterval(()=>{
                opacity-=0.05;   //加减有一定的偏差
                if(opacity < 0){
                    opacity=1;
                }
                this.setState({opacity});
            },500)
        }

        render(){
            let opacity=this.state.opacity;

            //虚拟DOM内写大括号,需要写2对{ }
            return (
                <div style={{opacity:opacity}}>xinyeshuaiqi.cn</div>
            )
        }
    }

    ReactDOM.render(<ShowSomething/>,document.getElementById('demo'));

</script>

</body>
</html>

最终显示效果:渲染的组件的文字随时间变透明

 

最后再来看下React的diff算法:

先贴上代码

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>React diff算法( 最小化页面重绘 )</title>
</head>
<body>
<div id="demo"></div>
<br>

<script src="../js/react.js"></script>
<script src="../js/react-dom.js"></script>
<script src="../js/babel.min.js"></script>
<script type="text/babel">

  class TimeRecord extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        date: new Date()
      };
    }

    componentDidMount () {
      setInterval(() => {
        this.setState({
          date: new Date()
        })
      }, 1000)   //每一秒钟更新一次  页面重绘一次
    }

    render () {
      console.log('render()调用...');

      /*观察在输入框内输入的东西,会不会每秒清空一次
      如果清空了,说明整个页面都随着state状态的改变而重绘
      如果没有清空,则说明重绘只是针对小范围的,即最小化页面重绘 (局部)
       */
      return (
          <p>
            <input type="text" placeholder="input something"/>!
            当前时间 :{this.state.date.toTimeString()}
          </p>
      );
    }
  }

  ReactDOM.render(
      <TimeRecord/>, document.getElementById('demo')
  );
</script>
</body>
</html>

 

文字随着时间推移,并没有刷新,说明这一部分并没有重新绘制,只是时间显示的这一部分变化,重新绘制,即最小页面重绘。

转载请注明:汪明鑫的个人博客 » React组件的生命周期

喜欢 (0)

说点什么

您将是第一位评论人!

提醒
avatar
wpDiscuz