React生命周期与钩子学习笔记 | 青训营

64 阅读4分钟

在 React 中,组件可以通过类组件和函数组件两种方式来定义。为了处理两种不同的组件在不同阶段的行为,React 提供了生命周期和钩子(Hooks)方法。

1. React的生命周期

在类组件中,生命周期方法用于控制组件在不同阶段的行为。以下是一些常用的生命周期方法:

  1. constructor(props) : 组件的构造函数,用于初始化 state 和绑定事件处理函数。
  2. componentDidMount() : 组件挂载后调用,常用于发起网络请求或订阅事件。
  3. componentDidUpdate(prevProps, prevState) : 组件更新后调用,可以比较前后状态或属性,执行相应的操作。
  4. shouldComponentUpdate(nextProps, nextState) : 决定组件是否需要更新,可根据新的属性和状态返回 true 或 false。
  5. componentWillUnmount() : 组件卸载前调用,用于清理资源、取消订阅等。
  6. static getDerivedStateFromProps(props, state) : 在组件更新前根据新的属性计算新的状态。
  7. getSnapshotBeforeUpdate(prevProps, prevState) : 在组件更新前获取 DOM 快照,常用于滚动位置的保持。

以下是一个简单的 React 类组件示例,展示了生命周期的使用:

import React, { Component } from 'react';

class LifecycleExample extends Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0,
    };
    console.log('Constructor called');
  }

  componentDidMount() {
    console.log('Component did mount');
    // 在组件挂载后开始计时器
    this.timerID = setInterval(() => {
      this.setState((prevState) => ({
        count: prevState.count + 1,
      }));
    }, 1000);
  }

  componentDidUpdate(prevProps, prevState) {
    console.log('Component did update');
    // 在状态更新后输出计数
    console.log('Previous Count:', prevState.count);
    console.log('Current Count:', this.state.count);
  }

  componentWillUnmount() {
    console.log('Component will unmount');
    // 在组件卸载前清理计时器
    clearInterval(this.timerID);
  }

  render() {
    console.log('Render called');
    return (
      <div>
        <h1>Lifecycle Example</h1>
        <p>Count: {this.state.count}</p>
      </div>
    );
  }
}

export default LifecycleExample;

在这个示例中,我们定义了一个名为 LifecycleExample 的类组件,使用了 constructorcomponentDidMountcomponentDidUpdatecomponentWillUnmount 生命周期方法。每个方法都会在特定的阶段调用,允许你执行相应的操作。在 componentDidMount 中,我们创建了一个计时器,更新计数器的状态。在 componentDidUpdate 中,我们输出了前一个状态和当前状态的计数值。在 componentWillUnmount 中,我们清除了计时器,以防止内存泄漏。

1. React的钩子(Hooks)

Hooks 是 React 16.8 引入的一种新特性,它允许函数组件拥有类似于生命周期的功能。以下是一些常用的钩子:

  1. useState(initialState) : 在函数组件中引入状态管理,返回状态和更新状态的函数。
  2. useEffect(callback, dependencies) : 在组件渲染后执行副作用操作(如数据获取、订阅等),可以通过第二个参数控制依赖变化时是否执行。
  3. useContext(context) : 获取上下文对象,使组件可以访问共享的数据。
  4. useReducer(reducer, initialState) : 在函数组件中使用 reducer 管理复杂的状态逻辑。
  5. useCallback(callback, dependencies) : 返回一个记忆的回调函数,依赖不变则返回旧的回调。
  6. useMemo(callback, dependencies) : 计算并返回记忆化的值,依赖不变则返回旧的值。
  7. useRef(initialValue) : 创建一个 ref 对象,可以在渲染之间存储可变值。
  8. useEffectCleanup(callback) : 在组件卸载时执行清理操作。

以下是一个简单的 React 函数组件示例,展示了Hooks的使用:

import React, { useState, useEffect } from 'react';

function HooksExample() {
  const [count, setCount] = useState(0);

  // 类似于 componentDidMount 和 componentDidUpdate 的效果
  useEffect(() => {
    console.log('Effect ran');
    // 在组件挂载后开始计时器
    const timerID = setInterval(() => {
      setCount(prevCount => prevCount + 1);
    }, 1000);

    // 返回清理函数,在组件卸载或状态更新前运行
    return () => {
      console.log('Cleanup ran');
      clearInterval(timerID);
    };
  }, []); // 空数组表示只在挂载和卸载时运行

  console.log('Render called');

  return (
    <div>
      <h1>Hooks Example</h1>
      <p>Count: {count}</p>
    </div>
  );
}

export default HooksExample;

在这个示例中,我们定义了一个名为 HooksExample 的函数组件,使用了 useStateuseEffect 钩子。useState 用于管理状态(计数器的值),而 useEffect 允许我们处理副作用操作和组件的生命周期。在 useEffect 中,我们通过传入一个回调函数来执行副作用操作。这个回调函数会在组件挂载后运行,并返回一个清理函数,在组件卸载或状态更新前运行。在这个例子中,我们创建了一个计时器并在清理函数中清除它,以防止内存泄漏。

与类组件不同,函数组件中的 Hooks 是根据调用顺序执行的,而不是按照生命周期的阶段来执行,同时避免了类组件中常见的一些问题,如 this 绑定。因此在大多数情况下,推荐使用函数组件和钩子,因为它们提供了更简洁、易于理解和维护的代码结构。