Skip to content
📈0️⃣

组件生命周期

React 组件的生命周期指的是从组件创建到被销毁的过程中经历的各个阶段,包括创建、挂载(Mounting)、更新(Updating)和卸载(Unmounting)等。具体如下:

生命周期

React 组件生命周期

1. 创建阶段

  • constructor:在组件实例被创建后立即调用,这是生命周期的开始。

2. 挂载阶段

  • getDerivedStateFromProps:在每次渲染前调用,用于根据 props 变化来更新 state(从 Props 派生 State:正如其名称所示,getDerivedStateFromProps 的目的是让组件能够根据传入的新 props 来派生出新的状态。这有助于确保组件的状态总是基于最新的 props)。
  • render:渲染组件输出,生成虚拟 DOM。
  • componentDidMount:在组件被插入到 DOM 后立即调用,此时可以执行一些如发起网络请求的操作。

3. 更新阶段

  • getDerivedStateFromProps:同挂载阶段,但在更新过程中也会触发 。
  • shouldComponentUpdate:是否应该更新组件, 在接收新的 props 或 state 后被调用, 返回一个布尔值来决定是否重新渲染。
  • render:同挂载阶段。
  • getSnapshotBeforeUpdate:更新前获取快照, 即将更新的 DOM 之前调用。
  • componentDidUpdate:组件已更新, 这里可以进行一些 DOM 操作。

4. 卸载阶段

  • componentWillUnmount:在组件即将从 DOM 中移除和销毁之前被立即调用,通常在这里进行一些如取消网络请求、清除定时器等清理工作。

需要注意的是,自 React 16.3 版本起,引入了新的 Hooks API,如 useStateuseEffect 等,这些 Hooks 在一定程度上改变了传统的类组件生命周期的概念。例如,useEffect Hook 可以在函数组件中模拟 componentDidMountcomponentDidUpdatecomponentWillUnmount 的功能。

总的来说,理解组件的生命周期对于开发复杂的 React 应用是非常重要的,它可以帮助我们更好地管理资源,优化性能,并保持组件状态的一致性。

代码与演示

以下是一个简单的 React 组件生命周期的代码案例:

1. 全部代码

点击查看代码
html
<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>test-react-lifecycle</title>
    <!-- <script src="https://cdn.staticfile.org/react/18.0.0/umd/react.development.js"></script>
    <script src="https://cdn.staticfile.org/react-dom/18.0.0/umd/react-dom.development.js"></script>
    <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script> -->
    <script src="./react.js"></script>
    <script src="./react-dom.js"></script>
    <script src="./babel.js"></script>
  </head>

  <body>
    <div id="app"></div>

    <script type="text/babel">
      // 案例: 1. React 组件生命周期
      const React = window.React;
      const Component = React.Component;
      const { createRoot } = ReactDOM;
      const { useState, useEffect } = React;
      window.list = [];

      // 1. 组件生命周期
      class MyComponent extends Component {
        // 1.1 创建阶段
        constructor(props) {
          super(props);
          this.state = {};
          list.push("1.1. 实例创建【创建-constructor】");
        }
        // 1.2 挂载阶段 - 挂载
        componentDidMount() {
          list.push("1.2. 组件挂载【挂载-componentDidMount】↑↑↑↑↑↑");
        }
        // 1.3 更新阶段 - 是否应该更新组件
        shouldComponentUpdate(nextProps, nextState) {
          const isUpdate = Math.random() > 0.5;
          list.push(
            "1.3. 更新阶段【是否更新-shouldComponentUpdate】" + isUpdate
          );
          return isUpdate;
        }
        // 1.3 更新阶段 - 静态方法 (从 Props 派生 State)
        static getDerivedStateFromProps(nextProps, prevState) {
          list.push(
            "1.3. 更新阶段【静态方法-getDerivedStateFromProps】--> 从 Props 派生 State"
          );
          // 根据新的 props 和当前的状态计算新的状态
          // 根据新的 props 和当前的状态计算新的状态
          const newState = { ...prevState, value: nextProps.value };
          return newState;
        }
        // 1.3 更新阶段 - 更新前获取快照 (Snapshot-快照)
        getSnapshotBeforeUpdate(prevProps, prevState) {
          list.push("1.3. 更新阶段【更新快照-getSnapshotBeforeUpdate】");
          return null;
        }
        // 1.3 更新阶段 - 组件完成更新后立即调用
        componentDidUpdate(prevProps, prevState, snapshot) {
          list.push("1.3. 更新阶段【更新完成-componentDidUpdate】↑↑↑↑↑↑");
        }
        // 1.4 卸载阶段
        componentWillUnmount() {
          list.push("1.4. 卸载阶段【componentWillUnmount】");
        }
        doUpdate(nextState = {}) {
          this.setState(nextState);
        }
        doClear() {
          list = [];
        }
        // 1.3 更新阶段 - 渲染DOM
        render() {
          list.push("1.3. 更新阶段【render DOM】");
          return (
            <div>
              <h3>MyComponent</h3>
              <button onClick={() => this.doUpdate()}>更新</button>
              <button onClick={() => this.doClear()}>清空</button>
            </div>
          );
        }
      }

      const Timeline = () => {
        const colorMap = {
          "1.1.": "#795548",
          "1.2.": "#2196f3",
          "1.3.": "#4caf50",
          "1.4.": "#ff9800",
        };
        const [count, setCount] = useState(0);
        useEffect(() => {
          setInterval(() => {
            setCount(Math.random());
          }, 100);
        }, []);
        return (
          <ol>
            {list.map((item, i) => (
              <li
                key={i}
                style={{
                  color: colorMap[item.split(" ")[0]],
                  border: "1px solid silver",
                  borderTop: i !== 0 ? "none" : "1px solid silver",
                }}
              >
                {item}
              </li>
            ))}
          </ol>
        );
      };

      const App = () => {
        const [state, setState] = useState(true);
        const reMount = () => {
          setState(false);
          setTimeout(() => {
            setState(true);
          }, 100);
        };
        return (
          <div>
            <button onClick={() => reMount()}>重新挂载 MyComponent</button>
            {state ? <MyComponent /> : ""}
            <Timeline />
          </div>
        );
      };
      const app = createRoot(document.getElementById("app"));
      app.render(<App />);
    </script>
  </body>
</html>

2. 案例演示




test-react-lifecycle.html 资源加载中...

在这个例子中,我们定义了一个名为 MyComponent 的类组件。在组件的生命周期中,我们可以看到以下方法被调用:

  • constructor:在实例被创建后立即调用,这是组件生命周期的开始。
  • componentDidMount:在组件被插入到 DOM 后立即调用,此时可以执行一些如发起网络请求的操作。
  • shouldComponentUpdate:在接收新的 props 或 state 后被调用,返回一个布尔值来决定是否重新渲染。
  • getSnapshotBeforeUpdate:在最近一次渲染输出(即即将更新的 DOM)之前调用,它使得组件能在发生更新前抓住一些信息。
  • componentDidUpdate:在组件完成更新后立即调用,这里可以进行一些 DOM 操作。
  • componentWillUnmount:在组件即将从 DOM 中移除和销毁之前被立即调用,通常在这里进行一些如取消网络请求、清除定时器等清理工作。
  • render:是组件的核心,负责渲染并返回虚拟 DOM。

需要注意的是,自 React 16.3 版本起,引入了新的 Hooks API,如 useStateuseEffect 等,这些 Hooks 在一定程度上改变了传统的类组件生命周期的概念。例如,useEffect Hook 可以在函数组件中模拟 componentDidMountcomponentDidUpdatecomponentWillUnmount 的功能。