zoukankan      html  css  js  c++  java
  • react组件的生命周期

    每个组件在网页中有自己的生命周期,生命周期可能会经历如下三个过程:

    • 装载过程(Mount):第一次在DOM树中渲染的过程
    • 更新过程(Update):组件被重新渲染的过程
    • 卸载过程(Unmount):组件从DOM中删除的过程

    三种不同的过程,React库会一次调用组件的一些成员函数,这些函数被称为组件的生命周期。所以,要定制一个React组件,实际上就是定制这些生命周期函数。

    装载过程

    当组件第一次被渲染时,依次调用如下函数:

    constructor

    在ES6的Class课程中,我们就已经详细的介绍过constructor相当于类的构造函数。比如:

    class Button extends React.Component {
        constructor() {
            ...
        }
        ....
    }
    

    以上代码的constructor就相当于

    function Button() {....}
    

    并不是每个组件都需要创建constructor,无状态的组件就不需要定义构造函数。一个React组件需要创建构造函数,往往因为如下原因:

    • 初始化state:组件生命周期中任何函数都可能需要访问state,constructor作为生命周期中第一个被调用的函数,自然也就成了初始化state的理想之地。
    • 绑定成员函数的this环境

    ES6的课程中我们介绍过Class的super:

    class ColorPoint extends Point {
      constructor(x, y, color) {
        //  相当于Point.call(this, x, y);
        // 调用父类的constructor(x, y)
        super(x, y);
        this.color = color;
        this.handleClick = this.handleClick.bind(this);
      }
      
      handleClick() {
          ....
      }
    }
    

    在子类的构造函数中,只有调用super之后才可以使用this。因为子类实例的构建,是基于对父类实例加工(即子类继承父类 Point.call(this, x, y) ),只有super方法才能返回父类。在上面的例子中,我们通过bind方法,让当前实例中的handleClick函数被调用时,this始终指向当前的组件实例。

    render

    一个React组件可以不定义其他所有函数,但一定要实现render函数,因为React.Component类对除render之外的生命周期函数都有默认实现。

    render函数不做实际的渲染工作,它只是返回一个JSX描述的结构。最终由React来操作渲染过程。如果一个组件不需要做任何渲染,那就让render返回null或false。

    render是一个纯函数,完全根据state和props来决定返回的结果,且不可在render中改变state,也就是说不可在render中调用this.setState。

    componentWillMount和componentDidMount

    componentWillMount和componentDidMount分别在render函数前后调用,正好做render函数前后必要的工作。

    componentWillMount发生在“将要装载”的时候,这个时候没有任何渲染结果,我们通常在服务端调用componentWillMount;在浏览器端,能在componentWillMount做的事情,我们都可以放在constructor中去完成。

    请看如下代码:

    class ControlPanel extends Component {
      render() {
        console.log('ControlPanel render');
        return (
          <div>
            <Counter caption="First"/>
            <Counter caption="Second" />
            <Counter caption="Third" />
          </div>
        );
      }
    }
    
    class Counter extends Component {
    
      constructor(props) {
         console.log('constructor: ' + props.caption);
        ......
      }
    
      componentWillMount() {
         console.log('componentWillMount:' + this.props.caption)
      }
    
      render() {
        console.log('render ' + this.props.caption);
        .....
        );
      }
    }
    

    结果如下:

    由于我们不做服务端渲染,所以在实际开发中,更关注componentDidMount。componentDidMount发生在组件已经被“装载”到DOM树的时候。此时,我们可以获取DOM。如果我们想让React和其他UI库配合,比如jQuery。需要注意的是:render函数被调用之后,componentDidMount并不会被立刻调用。

    class ControlPanel extends Component {
      render() {
        console.log('ControlPanel render');
        return (
          <div>
            <Counter caption="First"/>
            <Counter caption="Second" />
            <Counter caption="Third" />
          </div>
        );
      }
    }
    
    class Counter extends Component {
    
      constructor(props) {
         console.log('constructor: ' + props.caption);
        ......
      }
    
      componentWillMount() {
         console.log('componentWillMount:' + this.props.caption)
      }
    
      componentDidMount() {
        console.log('componentDidMount:' + this.props.caption)
      }
    
      render() {
        console.log('render ' + this.props.caption);
        .....
        );
      }
    }
    

    大家先想一下结果,然后在看结果图:

    我靠!怎么和我们想象的不一样,三个componentDidMount怎么都跑到最后才出现?

    原来,render函数本身并不往DOM树上直接渲染,它所做的仅仅是返回JSX。React库要把所有组件返回的结果综合起来,才能知道如何产生对应的DOM修改。

    更新过程

    当组件被装载到DOM树之后,要提供更好的交互体验,就要让该组件可以随着用户操作改变展现内容。当props和state被修改时,就会引发组件的更新过程。

    在16.3版本之前, 更新过程React的生命周期见下图:

    据官网介绍,17版本之后,在更新过程中React的生命周期会发生很大的变化,有些函数会被更改甚至废弃,这里我们只介绍最重要且最常用的函数shouldComponentUpdate。

    shouldComponentUpdate(nextProps, nextState)

    除了render函数之外,shouldComponentUpdate应该是React组件生命周期中最重要的函数。render函数决定了组件该渲染什么,shouldComponentUpdate决定了组件什么时候不需要渲染,这一点对于提高组件性能相当重要!

    render和shouldComponentUpdate是React组件生命周期中有且仅有需要返回结果的两个函数。render返回结果用于渲染组件,shouldComponentUpdate返回一个布尔值,告诉组件需不需要继续这次更新。shouldComponentUpdate返回true,则继续更新,调用render函数;返回false,则停止更新,不调用render函数。

    shouldComponentUpdate接受两个参数:nextProps和nextState,外加this.props和this.state来判断是返回true还是false。

    在前面的例子中,我们点击re-render按钮,输出结果:

    现在给counter组件添加shouldComponentUpdate函数:

    shouldComponentUpdate(nextProps, nextState) {
        return nextProps.caption !== this.props.caption || nextState.count !== this.state.count
    }
    

    再点击re-render按钮,结果如下图:

    可见,当counter组件上的caption或count属性不发生变化的时候,counter组件就不会再重复渲染。

    卸载过程

    React组件卸载过程只涉及一个函数componentWillUnmount。该函数在组件从DOM树上删掉之前调用,所以适合做一些清理工作。componentWillUnmount中的工作往往跟componentDidMount有关。如前面所说的在componentDidMount中引入jQuery创建DOM元素,那么在componentWillUnmount中就需要将这些创建的DOM元素清除掉,否则就会造成内存泄露。

  • 相关阅读:
    fwt
    fft,ntt
    loj6077
    高维前缀和
    hihocoder 1496 寻找最大值
    HDU 5977 Garden of Eden
    扩展crt
    有标号的DAG计数I~IV
    BZOJ 3160 万径人踪灭
    Codeforces Round #524 (Div. 2) F
  • 原文地址:https://www.cnblogs.com/renzhiwei2017/p/8796582.html
Copyright © 2011-2022 走看看