useMemo钩的作用是什么(附代码示例)

590 阅读2分钟

如果你还不熟悉钩子的概念,请务必查看 文章,因为它对钩子的概念提供了一个非常好的、深入的概述,以及一些钩子的例子。

简介

useMemo 钩子是用来返回一个缓存的值,以节省任何重新计算的开销。它的工作原理与useCallback 钩子类似;你可以在这里阅读更多关于它的信息。

useMemo 钩子被用来阻止一个组件重新渲染,除非它的道具发生了变化,这意味着我们现在可以隔离资源密集型的计算值,这样它们就不会在每个组件渲染时自动运行。

最好是展示一个有利于使用该钩子的场景,这样我们就能更好地理解我们为达成一个问题所采取的步骤,然后再解释使用useMemo 钩子背后的思考过程。

项目概述

我们将从搭建一个全新的React项目的脚手架开始。首先,我们将创建一个新的项目目录,之后,我们将使用终端初始化一个新项目。

在这个过程中,你可以使用npmnpx或者yarn。你要运行的命令是:

  • npmnpm init react-app app-name
  • npx: npx create-react-app app-name
  • yarnyarn create react-app app-name

现在我们已经设置好了一切,让我们直接进入有趣的部分。

项目进展

由于这是一个小项目,我们将把所有的代码放在根src 目录下的App.js 文件内,它看起来会是这样的:

import { useState } from "react";
import "./App.css";

const App = () => {
  const [count, setCount] = useState(0);
  const [todos, setTodos] = useState([]);

  const calculation = expensiveCalculation(count);

  const increment = () => {
    setCount((c) => c + 1);
  };

  const addTodo = () => {
    setTodos((t) => [...t, "New Todo"]);
  };

  return (
    <div className="App">
      <div>
        <h2>My Todos</h2>
        {todos.map((todo, index) => {
          return <p key={index}>{todo}</p>;
        })}
        <button onClick={addTodo}>Add Todo</button>
      </div>
      <hr />
      <div>
        Count: {count}
        <button onClick={increment}>+</button>
        <h2>Expensive Calculation</h2>
        {calculation}
      </div>
    </div>
  );
};

const expensiveCalculation = (num) => {
  console.log("Calculating...");

  for (let i = 0; i < 1000000000; i++) {
    num += 1;
  }

  return num;
};

export default App;

上面的应用程序相当简单,我们有一个todos列表,一个计数器元素,最后是一个函数,一旦调用,就会触发一些昂贵的计算。

你可以注意到,每次组件重新显示时都会调用这个函数。

那么,问题出在哪里?

当添加一个新的todo时,你会注意到在发生任何事情之前会有一个轻微的延迟。这是不应该的,因为无论从视觉上还是功能上,它们都是不相关的。

添加todo的延迟

问题的根本原因

延迟是由每次重新渲染App 组件时触发的昂贵计算造成的。App 组件的重新渲染是由其状态的变化引起的。

解决方案

这是一个使用useMemo 钩子的完美场景,因为它被设想为帮助我们在处理昂贵的计算时提高性能,如函数调用。

通过将我们的expensiveCalculation 函数调用包裹在useMemo 钩子中,我们将确保这个函数调用的结果只有在钩子作为辅助参数的依赖数组的值发生变化时才会被重新计算,否则它将被缓存起来,不会受到外部状态变化或组件重新渲染的影响。

有了useMemo ,我们的expensiveCalculation 函数反而会被这样使用。

const calculation = useMemo(() => expensiveCalculation(count), [count]);

通过将count 变量传递给useMemo's hook dependency array,我们让React知道,除非count 变量的值发生变化,否则我们要改变expensiveCalculation 函数调用的结果。

如果你现在尝试重新加载你的浏览器标签,并尝试添加一个新的todo,你将能够注意到它不再滞后了。

使用useMemo钩子后,缓存了昂贵的计算过程

这只会在更新count 状态变量的值时发生,这是预期的。

你可以在这里了解更多关于memo HoC的信息。其功能与useMemo 钩子类似,区别在于语法。你可以在这篇文章中查看一个实际的使用案例。

总结

我希望你喜欢阅读这篇文章,并希望你能更好地理解什么是useMemo 钩子,它的作用,以及你应该何时使用它。

如果你对这篇文章有任何问题、疑问或反馈,请随时在下面留下评论。

下一篇见。欢呼吧!