返回

React源码解析(二):组件的类型与生命周期

前端

在上一篇文章《React源码解析(一):组件的实现与挂载》中,我们阐述了React组件的实现和挂载。现在我们来一起探究组件的生命周期。

我们已经知道,只有在挂载流程开始后,才会触发组件的生命周期,生成ReactElement类型的js对象,通过解析组件对象内部所携带的信息,获得组件的类型、props和children等信息,从而创建出对应的组件实例。

React组件的生命周期分为四个阶段:

  1. 初始化阶段

    在这个阶段,React会创建组件实例,并调用组件的constructor方法。constructor方法中,我们可以初始化组件的状态和绑定事件处理函数。

  2. 挂载阶段

    在这个阶段,React会将组件实例挂载到DOM中。挂载是指将组件实例渲染成HTML元素,并插入到指定的位置。在挂载阶段,React会调用组件的componentDidMount方法。componentDidMount方法中,我们可以执行一些初始化操作,比如发送网络请求或设置定时器。

  3. 更新阶段

    当组件的状态或props发生变化时,React会触发组件的更新阶段。在更新阶段,React会调用组件的shouldComponentUpdate方法。shouldComponentUpdate方法中,我们可以决定是否需要更新组件。如果需要更新组件,React会调用组件的componentWillUpdate方法。componentWillUpdate方法中,我们可以执行一些更新前的操作,比如保存组件的状态。然后,React会调用组件的render方法,重新渲染组件。最后,React会调用组件的componentDidUpdate方法。componentDidUpdate方法中,我们可以执行一些更新后的操作,比如更新组件的DOM元素。

  4. 卸载阶段

    当组件从DOM中卸载时,React会调用组件的componentWillUnmount方法。componentWillUnmount方法中,我们可以执行一些卸载操作,比如清除定时器或取消网络请求。

组件的生命周期如下图所示:

[初始化阶段] -> [挂载阶段] -> [更新阶段] -> [卸载阶段]

组件的生命周期对于理解React的工作原理非常重要。通过对组件生命周期的理解,我们可以更好地掌握React的组件化思想,并编写出更健壮的React应用程序。

接下来,我们将详细介绍每个生命周期阶段的具体内容。

初始化阶段

在初始化阶段,React会创建组件实例,并调用组件的constructor方法。constructor方法中,我们可以初始化组件的状态和绑定事件处理函数。

初始化组件实例

组件实例是组件在内存中的表示。它包含组件的状态、props和children等信息。

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

    this.state = {
      count: 0
    };

    this.handleClick = this.handleClick.bind(this);
  }

  // 其他方法
}

在上面的代码中,我们定义了一个名为MyComponent的组件。在组件的constructor方法中,我们初始化了组件的状态和绑定了事件处理函数handleClick。

初始化组件状态

组件的状态是一个对象,它包含组件内部的数据。组件的状态可以通过this.setState()方法进行更新。

this.setState({
  count: this.state.count + 1
});

在上面的代码中,我们通过this.setState()方法将组件的状态count更新为count + 1。

绑定事件处理函数

事件处理函数是组件用来处理事件的方法。事件处理函数需要在constructor方法中绑定到组件实例上。

this.handleClick = this.handleClick.bind(this);

在上面的代码中,我们将事件处理函数handleClick绑定到了组件实例上。这样,当组件的DOM元素发生click事件时,就会调用组件的handleClick方法。

挂载阶段

在挂载阶段,React会将组件实例挂载到DOM中。挂载是指将组件实例渲染成HTML元素,并插入到指定的位置。在挂载阶段,React会调用组件的componentDidMount方法。

挂载组件实例

React会将组件实例挂载到DOM中。挂载是指将组件实例渲染成HTML元素,并插入到指定的位置。

ReactDOM.render(<MyComponent />, document.getElementById('root'));

在上面的代码中,我们将MyComponent组件实例挂载到了id为root的DOM元素中。

调用componentDidMount方法

在组件挂载完成后,React会调用组件的componentDidMount方法。componentDidMount方法中,我们可以执行一些初始化操作,比如发送网络请求或设置定时器。

componentDidMount() {
  // 发送网络请求
  fetch('https://example.com/api/data')
    .then(response => response.json())
    .then(data => {
      this.setState({
        data: data
      });
    });

  // 设置定时器
  this.timer = setInterval(() => {
    this.setState({
      count: this.state.count + 1
    });
  }, 1000);
}

在上面的代码中,我们在componentDidMount方法中发送了一个网络请求,并设置了一个定时器。

更新阶段

当组件的状态或props发生变化时,React会触发组件的更新阶段。在更新阶段,React会调用组件的shouldComponentUpdate方法。shouldComponentUpdate方法中,我们可以决定是否需要更新组件。如果需要更新组件,React会调用组件的componentWillUpdate方法。componentWillUpdate方法中,我们可以执行一些更新前的操作,比如保存组件的状态。然后,React会调用组件的render方法,重新渲染组件。最后,React会调用组件的componentDidUpdate方法。componentDidUpdate方法中,我们可以执行一些更新后的操作,比如更新组件的DOM元素。

触发更新阶段

组件的状态或props发生变化时,会触发组件的更新阶段。

this.setState({
  count: this.state.count + 1
});

在上面的代码中,我们将组件的状态count更新为count + 1。这会触发组件的更新阶段。

调用shouldComponentUpdate方法

在组件的更新阶段,React会首先调用组件的shouldComponentUpdate方法。shouldComponentUpdate方法中,我们可以决定是否需要更新组件。

shouldComponentUpdate(nextProps, nextState) {
  return this.state.count !== nextState.count;
}

在上面的代码中,我们判断组件的状态count是否发生变化。如果count发生变化,则返回true,表示需要更新组件。否则,返回false,表示不需要更新组件。

调用componentWillUpdate方法

如果shouldComponentUpdate方法返回true,React会调用组件的componentWillUpdate方法。componentWillUpdate方法中,我们可以执行一些更新前的操作,比如保存组件的状态。

componentWillUpdate(nextProps, nextState) {
  this.prevCount = this.state.count;
}

在上面的代码中,我们在componentWillUpdate方法中保存了组件的状态count。

调用render方法

在调用componentWillUpdate方法之后,React会调用组件的render方法。render方法中,我们可以返回组件的UI结构。

render() {
  return (
    <div>
      <h1>Count: {this.state.count}</h1>
      <button onClick={this.handleClick}>+</button>
    </div>
  );
}

在上面的代码中,我们返回了一个包含一个h1元素和一个button元素的UI结构。

调用componentDidUpdate方法

在调用render方法之后,React会调用组件的componentDidUpdate方法。componentDidUpdate方法中,我们可以执行一些更新后的操作,比如更新组件的DOM元素。

componentDidUpdate(prevProps, prevState) {
  if (this.prevCount !== this.state.count) {
    // 更新DOM元素
    this.refs.count.innerHTML = this.state.count;
  }
}

在上面的代码中,我们在componentDidUpdate方法中更新了DOM元素的innerHTML属性。

卸载阶段

当组件从DOM中卸载时,React会调用组件的componentWillUnmount方法。componentWillUnmount方法中,我们可以执行一些卸载操作,比如清除定时器或取消网络请求。

触发卸载阶段

当组件从DOM中卸载时,会触发组件的卸载阶段。

ReactDOM.unmountComponentAtNode(document.getElementById('root'));

在上面的代码中,我们将MyComponent组件实例从DOM中卸载。

调用componentWillUnmount方法

在组件的卸载阶段,React会调用组件的componentWillUnmount方法。componentWillUnmount方法中,我们可以执行一些卸载操作,比如清除定时器或取消网络请求。

componentWillUnmount() {
  // 清除定时器
  clearInterval(this.timer