返回

以 useEffect 与 React 组件的性能优化

前端

React 中 useEffect 使用问题

前言

最近看了一下 ant-design 中的 tree 组件源码时发现 useEffect 中根据 props 来计算当前函数组件的 state 的,感到好奇,因为这样会导致应用重新绘制一次,这样才导致组件 rerender,我看了源码后知道,这个 tree 组件的目的是为了复用一些子组件,减少重复渲染,但是这个操作就会导致组件重新渲染一次,性能会有损耗。

怎么解决这个问题呢?

第一种方法是使用 useMemo 将计算结果缓存起来,但是这种方式只适用于计算量较大的场景,如果计算量较小,使用这种方式反而会带来性能损耗。

第二种方法是使用 useRef 来存储计算结果,这种方式可以避免重新计算,但是需要手动管理计算结果的更新,相对来说比较麻烦。

第三种方法是使用 useReducer 来管理状态,这种方式可以避免重新计算,而且可以轻松地管理状态的更新,但是使用起来会比较复杂。

第四种方法是使用 useMutationEffect 来管理状态,这种方式可以避免重新计算,而且使用起来相对简单,但是它只适用于某些特定的场景。

在实际开发中,我们可以根据具体场景选择合适的方法来优化组件性能。

useEffect 的工作原理

useEffect 是 React 中的一个函数,用于在函数组件中管理状态和事件监听。它接受两个参数:一个回调函数和一个依赖项数组。回调函数会在组件第一次渲染后、每次更新后以及组件卸载前执行。依赖项数组用于控制组件的重新绘制。如果依赖项数组中的任何一项发生变化,组件就会重新绘制。

useEffect 的用法

在函数组件中使用 useEffect 来管理状态和事件监听,有以下几种方式:

  1. 使用 useEffect 来初始化状态
const MyComponent = () => {
  const [count, setCount] = useState(0);

  useEffect(() => {
    // 初始化状态
    setCount(10);
  }, []);
};
  1. 使用 useEffect 来监听事件
const MyComponent = () => {
  const [count, setCount] = useState(0);

  useEffect(() => {
    // 监听事件
    window.addEventListener("click", () => {
      setCount(count + 1);
    });

    // 清理事件监听器
    return () => {
      window.removeEventListener("click", () => {
        setCount(count + 1);
      });
    };
  }, []);
};
  1. 使用 useEffect 来控制组件的重新绘制
const MyComponent = ({ prop1, prop2 }) => {
  const [count, setCount] = useState(0);

  useEffect(() => {
    // 控制组件的重新绘制
    if (prop1 !== prevProp1 || prop2 !== prevProp2) {
      setCount(count + 1);
    }
  }, [prop1, prop2]);
};

useEffect 的注意事项

在使用 useEffect 时,需要注意以下几点:

  1. useEffect 的回调函数会在组件第一次渲染后、每次更新后以及组件卸载前执行。因此,在回调函数中不要执行一些开销较大的操作,例如网络请求或复杂的计算。
  2. useEffect 的依赖项数组用于控制组件的重新绘制。如果依赖项数组中的任何一项发生变化,组件就会重新绘制。因此,在选择依赖项时,要谨慎考虑。
  3. useEffect 可以用来管理状态和事件监听。但是,对于一些特定的场景,可以使用更适合的 API,例如 useReducer 或 useMutationEffect。