上节课我们了解了组件挂载到卸载这一整个生命周期的流程,但是我们好像并没有提到组件更新啊。那么这节课我们就来说一说关于更新。

回顾

在开始这节课之前,我们先来对上节课来做一个简单的回顾:

  • 单一组件挂载到卸载整个生命周期中有 5 个生命周期钩子被按顺序调用
  • constructor构造器方法
  • 在组件即将挂载之前调用componentWillMount方法
  • 调用render方法来挂载组件
  • 完成组件挂载后立即调用componentDidMount
  • 即将卸载前调用componentWillUnmount方法
  • 组件中各个生命周期钩子的定义顺序对程序执行没有影响,生命周期钩子执行的顺序依赖与生命周期的流程

以上便是上节课的主要知识点,那么接下来我们便来继续学习今天的课程:

流程图

我们还是要再借助一下流程图的,其实右边这一块其实就是组件的更新过程了,但是这个过程中有三个入口分别是:

  • 父组件的render
  • setState
  • forceUpdate

那么我们先走一个我们最熟悉的入口,setState这个我们用了多少次了都,这儿个就是最基本的更改状态来驱动页面更新嘛,两外两个入口我们之前仿佛根本就没有听过啊。那么好,我们就先从这个setState开始说起。

我们之前是不是说过,只要我们更新了state,那么就会重新调用render,但是实际上呢不仅仅是重新调用了render,其实还调用了其他的钩子。我们来看一下流程图:

当我们执行完setState之后,是不是马上到了shouldComponentUpdate?这个方法我们也没见过,这是什么意思啊?从名字上看就知道:组件是否应该更新。

其实这个方法其实就相当于一个阀门,当我们state更新之后,相当于程序去问shouldComponentUpdate方法,我应该更新组件吗?这就相当于一个阀门。如果这个方法返回了false,那么流程就此截止,页面就不会更新,反之如果返回值是true那么就会继续往后进行来到了componentWillUpdate方法。

这个方法我们也没见过,但是读一下名字是什么意思?组件即将更新。这个是不是和我们那个componentWillMount很类似啊?在更新之前做得准备工作。当这些准备工作做完了之后,直接再调用render方法来更新组件。

render执行完组件也完成了更新,那么立即调用componentDidUpdate。这个是不是和componentDidMount的性质一样?当完成什么什么条件之后马上执行什么什么。最后当我们即将卸载的时候就会来调用componentWillUnmount方法。

那么我们改一下代码看一下效果吧

class Count extends React.Component {
  state = { count: 0 };

  shouldComponentUpdate(){
    console.log("Count-shouldComponentUpdate");
    return true;
  }
  componentWillUpdate(){
    console.log("Count-componentWillUpdate");
  }
  componentDidUpdate(){
    console.log("Count-componentDidUpdate");
  }

  render() {
    console.log("Count-render");
    const { count } = this.state;
    return (
      <div>
        <h2>当前点击 {count} 次</h2>
        <button onClick={this.add}>Add</button>
        <button onClick={this.unmount}>Unmount</button>
      </div>
    );
  }

  add = () => {
    this.setState({ count: this.state.count + 1 });
  }
  unmount = () => {
    React.unmountComponentAtNode(document.getElementById("test"));
  }
}

这次我们的代码是不是看着就比之前有条理一点了?初始化状态,然后是生命周期的钩子,然后render方法,最后是我们自定义的事件回调函数。那么我们看一下效果吧:

image-20211230112733086

我们让shouldComponentUpdate方法返回true,然后点击按钮是不是就进入了后面的流程,但是为什么我们在Count-shouldComponentUpdate之前还打印了Count-render?我们是不是在挂载组件的时候就要调用一次render方法啊?所以会额外多出来这一行。那么我们让shouldComponentUpdate返回false的话会是什么结果呢?那么我们看一下效果:

image-20211230113022088

页面没有更新,但是调用了shouldComponentUpdate方法。所以这也印证了我们所说的shouldComponentUpdate方法其实就是一个阀门,只有当这个阀门打开才能继续后面更新的流程。

但是有人要说了,我们之前从来也没有写过shouldComponentUpdate方法,那么为什么我们执行了setStae为什么还是成功更新了呢?因为react底层会自动把shouldComponentUpdate方法补上,并且默认返回true。如果说我们写了这个方法并且让他返回false,那么页面将无法更新,但是有人说了,如果我写了shouldComponentUpdate方法,但是我没有返回值会怎么样呢?

我们都知道,每个函数都会默认有返回值是undefined,只有在你手动return了之后才会返回你手动return的值。但是undefined在这里到底是算true还是false呢?我们来试一下呗。把return这一行注释掉,来看看效果:

image-20211230113526116

出现了错误警告。但是shouldComponentUpdate成功调用了,而且页面也没有更新,那么说明undefined算是false的,但是这个错误却说,shouldComponentUpdate方法一定要返回true或者fales,所以说我们如果要写shouldComponentUpdate方法的话一定要返回一个明确的bool值。

以上就是整个组件更新的一个流程。

总结

  • 组件完成挂载并执行完了componentDidMount之后按顺序执行了 4 个生命周期钩子
  • 通过shouldComponentUpdate方法判断是否允许更新
  • 通过componentWillUpdate方法做更新前的准备工作
  • 通过render方法更新组件
  • 更新组件之后立即调用componentDidUpdate方法
  • shouldComponentUpdate必须返回bool类型
  • 如果没有写shouldComponentUpdate方法,react会自动补齐该方法,并且默认该方法返回true

Copyright statement:The articles of this site are all original if there is no special explanation, indicate the source please when you reprint.

Link of this article:https://work.lynchow.com/article/lifecycle_setstate_old/