useCallback 和 useMemo 有什么区别



也许我误解了什么,但每次重新渲染时都会运行useCallback Hook。

我传递了输入——作为useCallback的第二个参数——不可变的常量——但返回的内存化回调仍然在每次渲染时运行我昂贵的计算(我很确定——你可以在下面的片段中自己检查(。

我已经将useCallback更改为useMemo,并且useMemo按预期工作——在传递的输入更改时运行。而且真的可以记住昂贵的计算。

实例:

'use strict';
const { useState, useCallback, useMemo } = React;
const neverChange = 'I never change';
const oneSecond = 1000;
function App() {
const [second, setSecond] = useState(0);

// This 👇 expensive function executes everytime when render happens:
const calcCallback = useCallback(() => expensiveCalc('useCallback'), [neverChange]);
const computedCallback = calcCallback();

// This 👇 executes once
const computedMemo = useMemo(() => expensiveCalc('useMemo'), [neverChange]);

setTimeout(() => setSecond(second + 1), oneSecond);

return `
useCallback: ${computedCallback} times |
useMemo: ${computedMemo} |
App lifetime: ${second}sec.
`;
}
const tenThousand = 10 * 1000;
let expensiveCalcExecutedTimes = { 'useCallback': 0, 'useMemo': 0 };
function expensiveCalc(hook) {
let i = 0;
while (i < tenThousand) i++;

return ++expensiveCalcExecutedTimes[hook];
}
ReactDOM.render(
React.createElement(App),
document.querySelector('#app')
);
<h1>useCallback vs useMemo:</h1>
<div id="app">Loading...</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>

useMemo旨在运行函数,并在组件渲染时返回一个值(假设其中一个依赖项已更改(。useCallback打算在渲染时返回一个(已存储的(函数,但实际上还没有调用该函数;通常,您只需将此函数传递给onClick参数或类似的参数。

如果调用正确,您可以互换使用它们,例如,让useMemo返回一个函数相当于useCallback,或者使用useCallback然后调用返回的函数类似于useMemo

useMemo()使函数仅在输入更改时运行。否则,它将返回已存储(缓存(的结果。只建议将useMemo()用于涉及复杂计算(更复杂的时间(的函数,因为运行useMemo()会有成本

useCallback()防止在每个重新提交器上创建函数的新实例(我的意思是函数被重新定义(,因此,如果我们将函数作为道具传递给子组件,则防止重新提交子组件

如今(2020年5月25日(,useCallbackuseMemo可以互换使用:

const fn = () => { function code }
const fn1 = React.useCallback(fn, deps)
const fn2 = React.useMemo(() => fn, deps)

在这两种情况下,fn1和fn2都保存在不同的渲染之间。不同的是,useCallback在未来可能会得到改进,它总是返回相同的函数,并将其中继到传递给它的最后一个函数

我在这里写过。

在您的示例中,useCallback中的函数expensiveCalc将在每次渲染时运行,因为您在每次渲染中都调用useCallback正下方的内存化函数。

useCallback将记忆并返回实际函数,因此即使函数被记忆,它仍然会在您调用它时运行。

在这个例子中,这基本上就是正在发生的事情:

const calcCallback = () => expensiveCalc('useCallback');
const computedCallback = calcCallback();

在您的情况下,不应使用useCallback

如果可能,将昂贵的函数移到react组件之外,并在外部执行。例如:

const calcResult = expensiveCalc('useCallback');
function App() {

如果出于某种原因,这是不可能的,这就是useMemo适用的地方。

useMemo将记住从函数返回的值,并在渲染之间保持它,直到依赖项发生变化。

这意味着如果您不想在每个渲染上运行昂贵的函数,而只想要该值,则将其移出react组件的范围或使用useMemo

有关这两个钩子的更多细节和信息,你可以在本文中阅读更多:useMemo和useCallback之间的区别是什么?

相关内容

  • 没有找到相关文章

最新更新