memo 与 useMemo

85 阅读2分钟

memo是个API,useMemo是个Hook。这两个都可以进行性能的优化。作用就是缓存,一个相对于某个函数,一个相对于组件。

memo

组件在 props 没有改变的情况下跳过重新渲染。

import { memo, useState } from 'react';

export default function MyApp() {
  const [name, setName] = useState('');
  const [address, setAddress] = useState('');
  return (
    <>
      <label>
        Name{': '}
        <input value={name} onChange={e => setName(e.target.value)} />
      </label>
      <label>
        Address{': '}
        <input value={address} onChange={e => setAddress(e.target.value)} />
      </label>
      <Greeting name={name} />
    </>
  );
}

const Greeting = memo(function Greeting({ name }) {
  console.log("Greeting was rendered at", new Date().toLocaleTimeString());
  return <h3>Hello{name && ', '}{name}!</h3>;
});

在第十行的input中输入东西,Greeting才会重新渲染,因为使用了memo,传入的props只有name

useMemo

useMemo(calculateValue, dependencies)

calculateValue:要缓存计算值的函数,return计算结果。

dependencies:一个数组,如果 dependencies 没有发生变化,React 将直接返回相同值。使用 Object.is 将每个依赖项与其之前的值进行比较。

[!tip] Object.is(),非常严格的判断,带不同符号的0都视为不相等,与===相比,对NaN的判断更加宽松。

看看官网的例子

import { useMemo } from 'react';

function TodoList({ todos, tab, theme }) {
  const visibleTodos = useMemo(() => filterTodos(todos, tab), [todos, tab]);
  // ...
}

只有todos, tab发生变化,filterTodos才会重新计算。

memo 与 useMemo结合使用

场景:

import React, { useMemo, useState } from 'react';
import { memo } from 'react';

// 一个昂贵的计算函数,我们不希望在每次渲染时都调用它
function expensiveComputation(numbers) {
  return numbers.reduce((sum, num) => sum + num, 0);
}

// 组件
const ListComponent = ({ numbers }) => {
  const [count, setCount] = useState(0);

  // 使用useMemo来缓存计算结果
  const total = useMemo(() => expensiveComputation(numbers), [numbers]);

  return (
    <div>
      <h1>Total: {total}</h1>
      <button onClick={() => setCount(count + 1)}>Click me ({count} clicks)</button>
    </div>
  );
};

// 使用memo来防止无关状态更新导致的重新渲染
export default memo(ListComponent);

useMemo确保只有当numbers数组改变时expensiveComputation函数才会重新计算。而memo确保只有当numbers数组本身发生改变时,ListComponent才会重新渲染。如果只是点击按钮改变count状态,组件不会进行不必要的重新渲染。

如果没有使用这种方式优化,函数和组件会进行多余的计算和渲染。