上节课我们引出了有关生命周期的概念,大了解了概生命周期的大致轮廓。接下来我们就要正式详细介绍一下生命周期了。

回顾

在开始新课程的讲解之前,我们先来对上节课的知识点做一个大致的回顾。

  • 组件渲染就是组件挂载,清空组件就是组件卸载
  • 组件在挂载完成之后会自动调用componentDidMount方法
  • 组件在卸载之前会自动调用componentWillUnmount

以上便是上节课的主要知识点,接下来开始我们这节课的内容。

生命周期的理解

上节课我们虽然说是拿人来类比了一下,但是生命周期到底怎么理解?我们知道react把一个组件从挂载到卸载这一个生命周期中会在特定的时间来做特定的事情。但是我们不能老师这么说啊,面试的时候面试官问生命是生命周期,我们这么回答肯定是不行的。那么生命周期应该怎么理解呢?

  1. 组件从创建到释放会经历一系列的特定阶段
  2. React组件中包含一系列的钩子函数(生命周期回调函数)会在特定的时刻调用
  3. 我们在定义组件时,会在特定的生命周期回调函数中做特定的工作

生命周期流程图(旧)

大家看上面这副图,这就是生命周期的流程图,当然这是一个旧版本的生命周期的流程图。我们先来将旧版本,待大家理解了旧版本之后再来学习新版本。

生命周期流程图的理解

当然这图看着是不是感觉有些不太明白?那么我们根据这幅图来做一个小案例,通过案例来理解这个流程。我们用最简单的计数器案例。

大概什么需求呢:

  • 一行文字和一个按钮
  • 文字最开始是 0
  • 点击按钮,文字就加一

那么我们还是按部就班地来,先实现基础页面:

class Count extends React.Component {
  render() {
    return (
      <div>
        <h2>当前点击 0</h2>
        <button>Add</button>
      </div>
    );
  }
}
ReactDOM.render(<Count />, document.getElementById("test"));

上面这段代码是不是就让页面上来展示我们想要展示的元素。但是整个页面还没有添加相应的交互,我们先来看一下效果

image-20211230095032301

这样我们的页面完成了,那么我们来添加交互,我们点击按钮的时候要变更这里的次数,每次加一,所以说我们得依赖state来完成这一操作。而且,我们是点击按钮来完成state更新的,所以说我们还得田间onClick回调。那么我们来更新一下代码:

class Count extends React.Component {
  state = { count: 0 }
  render() {
    return (
      <div>
        <h2>当前点击 {this.state.count} 次</h2>
        <button onClick={this.add}>Add</button>
      </div>
    );
  }
  add = () => {
    let {count} = this.state;
    count+=1;
    this.setState({ count });
  }
}

我们来看一下,我是不是在最一开始初始化state?然后把statecount属性设为 0 。然后给<button>添加了onClick回调,然后定义add方法来更新state从而来实现点击按钮更新state来驱动页面完成更新。那么我们来看一下效果:

image-20211230095941547

我们已经可以完成点击按钮实现点击次数加一了。

生命周期流程

刚刚那个案例也是再简单不过了。只要看两节可基本就能写出来这么一个案例。但是写这个案例不是我们的目的,那么我们接下来在这个案例里面来测试一下刚才的生命周期流程图。

目前我们这个案例里面是不是就只有一个组件?没有图中所说的父组件。那么我们就先只看挂载时的这一部分流程:

class Count extends React.Component {
  constructor(props) {
    console.log("Count-constructor");
    super(props);
    this.state = { count: 0 };
  }
  render() {
    console.log("Count-render")
    return (
      <div>
        <h2>当前点击 {this.state.count} 次</h2>
        <button onClick={this.add}>Add</button>
        <button onClick={this.unmount}>Unmount</button>
      </div>
    );
  }
  unmount = () => {
    ReactDOM.unmountComponentAtNode(document.getElementById("test"));
  }
  componentWillMount(){
    console.log("Count-componentWillMount");
  }
  componentWillUnmount(){
    console.log("Count-componentWillUnmount");
  }
  componentDidMount(){
    console.log("Count-componentDidMount");
  }
  add = () => {
    let {count} = this.state;
    count+=1;
    this.setState({ count });
  }
}
ReactDOM.render(<Count />, document.getElementById("test"));

首先,什么叫挂载?是不是这个组件第一次渲染到页面?流程图中说挂载时第一步就会调用构造器方法但是我们没有写构造器啊。没关系,虽然说我们日常开发都不写构造器,但是为了测试这个流程那我们加上呗。那么既然加了构造器方法,state是不是也就应该卸载构造器中了?

然后我们再看,调了构造器之后紧接着调用了componentWillMount,从字面上来看就能明白,组件即将挂载,但是我们之前也一直没有用过,那么我们现在也来测试一下呗,我们在代码中也加上这个方法。

紧接着流程图就中就到了render方法,这个我们已经很熟悉了,等调用完render之后就会调用componentDidMount方法,我们见到这个方法是不是就明白了,这个时候组件其实已经完成了挂载。在整个流程的最后调用的是componentWillUnmount方法,到此流程结束,一次完整的生命周期结束。因为组件都卸载了就不可能再调用其他的了,这个组件的这一次生命已经完结了。

所以我们在代码中加上相应的方法,然后我们来想一下,如果按照这个流程来走的话控制台是不是会依次打印出Count-constructorCount-componentWillMountCount-renderCount-componentDidMount,最后是Count-componentWillUnmount?那么我们来看一下效果:

image-20211230103202943

我们一下,诶?前面 4 个确实按照我们预期的顺序打印出来了,但是Count-componentWillUnmount为什么没有打印出来呢?因为我们还没有卸载这个组件。那么我们点击一下unmount按钮:

image-20211230103346200

组件卸载了,然后Count-componentWillUnmount打印出来了。大家看我组件中的代码是不是感觉有点写得乱七八糟的?我是故意打乱了各个方法的顺序。因为曾经我突然想过这样一个问题,我组件中生命周期钩子定义的顺序会不会影响代码的执行呢?当惹从这个结果大家很明显地了解到,我们组件中各个生命周期钩子定义的顺序是不会对程序执行有任何影响的。

至此我们便讲完了单一组件生命周期从挂载到卸载的流程。

总结

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

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_mount_old/