简介
useMemo 钩子是用来返回一个缓存的值,以节省任何重新计算的开销。它的工作原理与useCallback 钩子类似;你可以在这里阅读更多关于它的信息。
useMemo 钩子被用来阻止一个组件重新渲染,除非它的道具发生了变化,这意味着我们现在可以隔离资源密集型的计算值,这样它们就不会在每个组件渲染时自动运行。
最好是展示一个有利于使用该钩子的场景,这样我们就能更好地理解我们为达成一个问题所采取的步骤,然后再解释使用useMemo 钩子背后的思考过程。
项目概述
我们将从搭建一个全新的React项目的脚手架开始。首先,我们将创建一个新的项目目录,之后,我们将使用终端初始化一个新项目。
在这个过程中,你可以使用npm、npx或者yarn。你要运行的命令是:
npm。npm init react-app app-name
npx: npx create-react-app app-name
yarn。yarn 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 钩子,它的作用,以及你应该何时使用它。