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元素清除掉,否则就会造成内存泄露。

  • 相关阅读:
    HDU 1863 畅通工程(Kruskal)
    HDU 1879 继续畅通工程(Kruskra)
    HDU 1102 Constructing Roads(Kruskal)
    POJ 3150 Cellular Automaton(矩阵快速幂)
    POJ 3070 Fibonacci(矩阵快速幂)
    ZOJ 1648 Circuit Board(计算几何)
    ZOJ 3498 Javabeans
    ZOJ 3490 String Successor(模拟)
    Java实现 LeetCode 749 隔离病毒(DFS嵌套)
    Java实现 LeetCode 749 隔离病毒(DFS嵌套)
  • 原文地址:https://www.cnblogs.com/renzhiwei2017/p/8796582.html
Copyright © 2011-2022 走看看