理解 useMemo、useCallback 和 memo

理解 useMemo、useCallback 和 memo ByAI

5月 15, 2024
ByAI, Frontend, React

虽然 React 的官方文档已经写的很清楚了,但我还是想总结下。形而上地讲前两个是 Hook,而 memo 是 API。形而下地说,useMemouseCallbackReact.memo 是 React 中用于优化性能的工具,它们帮助你避免不必要的重新渲染。

以下是它们的区别和使用示例。

1. useMemo #

useMemo 用于记住计算结果,只有当依赖项发生变化时才重新计算。这对于昂贵的计算特别有用。

语法 #

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

示例 #

import React, { useMemo } from 'react';

function ExpensiveComponent({ a, b }) {
  const expensiveValue = useMemo(() => {
    // 假设这是一个昂贵的计算
    return a + b;
  }, [a, b]);

  return <div>{expensiveValue}</div>;
}

值得注意的是,如果 a 或 b 是 useState,并且发生了变化,那么 expensiveValue 的改变也会触发重新渲染。

2. useCallback #

useCallback 用于记住函数实例,只有当依赖项发生变化时才重新创建。这对于传递给子组件的回调函数特别有用,防止子组件不必要的重新渲染。

⚠️ 虽然每次函数的参数可能一样,但是每次要渲染子组件时因为函数实例的变化,还是会被 Object.is 认为传入了新的值,即会触发子组件的重新渲染,从而造成性能开销。更好的做法是不仅要使用 useCallback,还要尽量使用 updater function 来消除 useCallback 函数的第二个参数的数量,使其为空最好,从而达到整个生命周期都不会触发重新渲染的效果。

语法 #

const memoizedCallback = useCallback(() => {
  doSomething(a, b);
}, [a, b]);

示例 #

import React, { useCallback } from 'react';

function ChildComponent({ onClick }) {
  return <button onClick={onClick}>Click me</button>;
}

function ParentComponent() {
  const handleClick = useCallback(() => {
    console.log('Button clicked');
  }, []);

  return <ChildComponent onClick={handleClick} />;
}

3. React.memo #

React.memo 是一个高阶组件,用于记住组件的渲染结果,只有当 props 发生变化时才重新渲染。这对于函数组件特别有用,防止不必要的重新渲染。

语法 #

const MemoizedComponent = React.memo(Component);

示例 #

import React from 'react';

const ChildComponent = React.memo(({ value }) => {
  console.log('ChildComponent rendered');
  return <div>{value}</div>;
});

function ParentComponent() {
  const [count, setCount] = React.useState(0);
  const [value, setValue] = React.useState('Hello');

  return (
    <div>
      <button onClick={() => setCount(count + 1)}>Increment Count</button>
      <ChildComponent value={value} />
    </div>
  );
}

如何理解和选择 #

  1. useMemo

    • 使用场景:当你有一个昂贵的计算,并且希望在依赖项不变的情况下避免重复计算。
    • 使用方法:将昂贵的计算放在 useMemo 的回调函数中,并提供依赖项数组。
  2. useCallback

    • 使用场景:当你需要将一个回调函数传递给子组件,并且希望在依赖项不变的情况下避免重新创建函数实例。
    • 使用方法:将回调函数放在 useCallback 的回调函数中,并提供依赖项数组。
  3. React.memo

    • 使用场景:当你有一个纯函数组件,并且希望在 props 不变的情况下避免重新渲染。
    • 使用方法:将组件包裹在 React.memo 中。

总结 #

  • 使用 useMemo 记住昂贵的计算结果。
  • 使用 useCallback 记住回调函数实例。
  • 使用 React.memo 记住组件的渲染结果。

通过合理使用这些工具,你可以显著优化 React 应用的性能,避免不必要的重新渲染。

本文共 956 字,上次修改于 Oct 14, 2024,以 CC 署名-非商业性使用-禁止演绎 4.0 国际 协议进行许可。

相关文章

» CSS 中的 inherit 选项

» 了解下 MobX 概念

» 了解下 Redux 概念

» tar 命令中的绝对路径和相对路径使用注意

» CSS 布局概览