useMemo在每次重新渲染的时候能够缓存计算的结果。
在初次渲染时,useMemo 返回调用 calculateValue 的结果。
在接下来的渲染中,如果依赖项没有发生改变,它将返回上次缓存的值;否则将再次调用 calculateValue,并返回最新结果。
尽管在某些情况下您可以不使用它,但对于需要进行昂贵的计算或处理大量数据的情况,使用 useMemo 是非常有益的。

calculateValue:要缓存计算值的函数。它应该是一个没有任何参数的纯函数,并且可以返回任意类型。在之后的渲染中,如果 dependencies 没有发生变化,React 将直接返回相同值。否则,将会再次调用 calculateValue 并返回最新结果,然后缓存该结果以便下次重复使用。
dependencies:所有在 calculateValue 函数中使用的响应式变量组成的数组。响应式变量包括 props、state 和所有你直接在组件中定义的变量和函数。

const cachedValue = useMemo(() => calculateValue, dependencies)

在严格模式下,为了 帮你发现意外的错误,React 将会 调用你的计算函数两次。
你可以仅仅依赖 useMemo 作为性能优化手段。否则,使用 state 变量 或者 ref 可能更加合适。

你应该仅仅把 useMemo 作为性能优化的手段。如果没有它,你的代码就不能正常工作,那么请先找到潜在的问题并修复它。然后再添加 useMemo 以提高性能。

默认情况下,当一个组件重新渲染时,React 会递归地重新渲染它的所有子组件。

记忆另一个 Hook 的依赖

依赖这样的对象会破坏记忆化。当组件重新渲染时,组件主体内的所有代码都会再次运行。创建 searchOptions 对象的代码行也将在每次重新渲染时运行。因为 searchOptions 是你的 useMemo 调用的依赖项,而且每次都不一样,React 知道依赖项是不同的,并且每次都重新计算 searchItems。

function Dropdown({ allItems, text }) {
  const searchOptions = { matchMode: 'whole-word', text };

  const visibleItems = useMemo(() => {
    return searchItems(allItems, searchOptions);
  }, [allItems, searchOptions]); // 🚩 提醒:依赖于在组件主体中创建的对象
  // ...

要解决此问题,你可以在将其作为依赖项传递之前记忆 searchOptions 对象 本身:

function Dropdown({ allItems, text }) {
  const searchOptions = useMemo(() => {
    return { matchMode: 'whole-word', text };
  }, [text]); // ✅ 只有当 text 改变时才会发生改变

  const visibleItems = useMemo(() => {
    return searchItems(allItems, searchOptions);
  }, [allItems, searchOptions]); // ✅ 只有当 allItems 或 serachOptions 改变时才会发生改变
  // ...

记忆一个函数

export default function Page({ productId, referrer }) {
  const handleSubmit = useMemo(() => {
    return (orderDetails) => {
      post('/product/' + productId + '/buy', {
        referrer,
        orderDetails
      });
    };
  }, [productId, referrer]);

  return <Form onSubmit={handleSubmit} />;
}
export default function Page({ productId, referrer }) {
  const handleSubmit = useCallback((orderDetails) => {
    post('/product/' + productId + '/buy', {
      referrer,
      orderDetails
    });
  }, [productId, referrer]);

  return <Form onSubmit={handleSubmit} />;
}

上面两个例子是完全等价的。useCallback 的唯一好处是它可以让你避免在内部编写额外的嵌套函数。

每次重新渲染时计算函数都会运行两次
在 严格模式 中,React 将调用你的某些函数两次而不是一次:

故障排查
我调用的 useMemo 应该返回一个对象,但返回了 undefined

这段代码不起作用:
 // 🔴 你不能像这样 `() => {` 在箭头函数中直接返回一个对象
  const searchOptions = useMemo(() => {
    matchMode: 'whole-word',
    text: text
  }, [text]);
请显式编写 return 语句:
  // ✅ 这有效并且是明确的
  const searchOptions = useMemo(() => {
    return {
      matchMode: 'whole-word',
      text: text
    };
  }, [text]);
Logo

基于 Vue 的企业级 UI 组件库和中后台系统解决方案,为数万开发者服务。

更多推荐