How to useMemo in React【译】

347 阅读2分钟

原文链接www.robinwieruch.de/react-useme…

React 的 useMemo Hook 可用于优化 React 函数组件的计算成本。 我们先通过一个示例组件来说明问题,然后再用 React 的 useMemo Hook 解决。 请记住,React 中的大多数性能优化都为时过早。 默认情况下,React 速度很快,因此每项性能优化都是可选的,以防某些事情开始变得缓慢。

注意:不要将 React 的 useMemo Hook 与 React 的mome API 混淆。 useMemo 用于记忆值,而 React memo 用于包装 React 组件以防止重新渲染。

注意:不要将 React 的 useMemo Hook 与 React 的 useCallback Hook 混淆。 useMemo 用于记忆值,而 useCallback 用于记忆函数。

让我们看下面的 React 应用程序示例,它呈现用户列表并允许我们按用户名过滤用户。问题:过滤器仅在用户明确单击按钮时发生;当用户输入输入字段时还没有:

import React from 'react';
 
const users = [
  { id: 'a', name: 'Robin' },
  { id: 'b', name: 'Dennis' },
];
 
const App = () => {
  const [text, setText] = React.useState('');
  const [search, setSearch] = React.useState('');
 
  const handleText = (event) => {
    setText(event.target.value);
  };
 
  const handleSearch = () => {
    setSearch(text);
  };
 
  const filteredUsers = users.filter((user) => {
    return user.name.toLowerCase().includes(search.toLowerCase());
  });
 
  return (
    <div>
      <input type="text" value={text} onChange={handleText} />
      <button type="button" onClick={handleSearch}>
        Search
      </button>
 
      <List list={filteredUsers} />
    </div>
  );
};
 
const List = ({ list }) => {
  return (
    <ul>
      {list.map((item) => (
        <ListItem key={item.id} item={item} />
      ))}
    </ul>
  );
};
 
const ListItem = ({ item }) => {
  return <li>{item.name}</li>;
};
 
export default App;

即使当有人在输入字段中键入时,filteredUsers 不会改变,因为它们仅在通过搜索状态单击按钮时才会改变,过滤器的回调函数会为输入字段中的每次按键一次又一次地运行(译者注:这里ListItem传入的是数组,数组的引用每次都不一样,因此React视为不等,所以每次重新渲染ListItem, 从而执行filteredUsers)。

这不会减慢这个小型 React 应用程序的速度。但是,如果我们要处理这个数组中的大量数据并为每次击键都运行过滤器的回调函数,我们可能会减慢应用程序的速度。因此,您可以使用 React 的 useMemo Hook 来记忆函数的返回值,并仅在其依赖项(此处搜索)发生更改时才运行函数:

function App() {
  ...
 
  const filteredUsers = React.useMemo(
    () =>
      users.filter((user) => {
        console.log('Filter function is running ...');
        return user.name.toLowerCase().includes(search.toLowerCase());
      }),
    [search]
  );
 
  ...
}

现在,这个函数只在搜索状态改变时执行。如果文本状态更改,它不会运行,因为这不是此过滤器函数的依赖项,因此也不是 useMemo 挂钩的依赖项数组中的依赖项。自己尝试一下:在输入字段中输入内容不应触发console.log,但通过单击按钮执行搜索会触发它。

毕竟,您可能想知道为什么不在所有值计算中使用 React 的 useMemo Hook,或者为什么 React 的 useMemo Hook 不是所有值计算的默认设置。在内部,React 的 useMemo Hook 必须在每次重新渲染时比较依赖项数组中的依赖项,以决定是否应该重新计算该值。通常,这种比较的计算可能比重新计算值更昂贵。总之,React 的 useMemo Hook 用于记忆值。