返回

React 系列 (3) —— 生命周期与 diff 算法: 一个从 0 实现 React 的过程

前端

从 0 实现 React 系列 —— 3.生命周期和 diff 算法

在构建一个迷你 React 框架的过程中,生命周期和 diff 算法是不可或缺的重要部分。让我们深入探讨这两者的细节,并通过示例和代码片段来了解它们如何在 React 中发挥作用。

1. 组件生命周期

组件生命周期是指一个组件从创建到销毁的整个生命周期中所经历的各个阶段,React 通过生命周期方法来允许组件在每个阶段执行特定的逻辑。组件生命周期主要分为三个阶段:

  • 挂载阶段: 当组件被创建并插入到 DOM 中时,会依次触发 constructorcomponentWillMountrendercomponentDidMount 这四个生命周期方法。
  • 更新阶段: 当组件的属性或状态发生变化时,会依次触发 componentWillReceivePropsshouldComponentUpdatecomponentWillUpdaterendercomponentDidUpdate 这五个生命周期方法。
  • 卸载阶段: 当组件从 DOM 中移除时,会触发 componentWillUnmount 生命周期方法。

2. diff 算法

diff 算法是 React 用于比较组件及其子组件在两次渲染之间的差异的核心算法。它通过比较新旧虚拟 DOM 树来确定哪些部分发生了变化,并仅更新那些发生变化的部分,从而最大限度地减少对 DOM 的操作,提高渲染性能。

React 的 diff 算法主要分为三个步骤:

  1. 比较根节点: 首先,比较新旧虚拟 DOM 树的根节点,如果根节点相同,则继续比较其子节点;如果根节点不同,则直接替换旧根节点。
  2. 比较兄弟节点: 对于新旧虚拟 DOM 树中的兄弟节点,从左到右依次比较,如果节点相同,则继续比较其子节点;如果节点不同,则直接替换旧节点。
  3. 比较子节点: 对于新旧虚拟 DOM 树中的子节点,采用递归的方式进行比较。如果子节点相同,则继续比较其子节点;如果子节点不同,则直接替换旧子节点。

3. 代码示例

为了更好地理解生命周期和 diff 算法,我们通过一个简单的示例来说明它们如何在 React 中协同工作。假设我们有一个 Counter 组件,它包含一个状态变量 count 和一个 incrementCount 方法,用于递增 count 的值。

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }

  componentWillMount() {
    console.log('组件即将挂载');
  }

  render() {
    return (
      <div>
        <h1>计数: {this.state.count}</h1>
        <button onClick={this.incrementCount}>递增</button>
      </div>
    );
  }

  componentDidMount() {
    console.log('组件已挂载');
  }

  componentWillReceiveProps(nextProps) {
    console.log('组件即将接收新的属性', nextProps);
  }

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

  componentWillUpdate(nextProps, nextState) {
    console.log('组件即将更新', nextProps, nextState);
  }

  componentDidUpdate(prevProps, prevState) {
    console.log('组件已更新', prevProps, prevState);
  }

  componentWillUnmount() {
    console.log('组件即将卸载');
  }

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

当我们渲染这个组件时,会依次触发 constructorcomponentWillMountrendercomponentDidMount 这四个生命周期方法。

constructor()
componentWillMount()
render()
componentDidMount()

当我们点击递增按钮时,会调用 incrementCount 方法,该方法会更新组件的状态,从而触发 componentWillReceivePropsshouldComponentUpdatecomponentWillUpdaterendercomponentDidUpdate 这五个生命周期方法。

componentWillReceiveProps()
shouldComponentUpdate() // 返回 true
componentWillUpdate()
render()
componentDidUpdate()

当我们卸载这个组件时,会触发 componentWillUnmount 生命周期方法。

componentWillUnmount()

通过这个示例,我们可以看到生命周期和 diff 算法是如何在 React 中协同工作,以管理组件的生命周期和高效地更新 DOM。