也许我误会了一些东西,但是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>
答案 0 :(得分:3)
useMemo
用于在组件渲染时运行该函数并返回一个值(假设依赖关系之一已更改)。 useCallback
旨在在渲染时返回一个(记忆的)函数,但实际上尚未调用该函数;通常,您只需将此函数传递给onClick
参数或类似的东西即可。
如果调用正确,则可以互换使用它们,例如让useMemo
返回一个函数等效于useCallback
,或者使用useCallback
然后调用返回的函数类似于{{ 1}}
答案 1 :(得分:3)
useMemo()
使函数仅在输入更改时运行。否则,它返回备忘(缓存)结果。仅建议将useMemo()
用于涉及复杂计算(时间复杂度更高)的函数,因为运行useMemo()
useCallback()
防止在每次重新渲染时都创建该函数的新实例(我的意思是重新定义了函数),因此,如果我们将子函数作为道具传递给子组件,则可以防止子组件的重新渲染。
答案 2 :(得分:0)
现在(2020年5月25日),useCallback
和useMemo
可互换使用:
const fn = () => { function code }
const fn1 = React.useCallback(fn, deps)
const fn2 = React.useMemo(() => fn, deps)
在两种情况下,fn1和fn2都保存在不同的渲染之间。 区别在于useCallback将来可能会有所改进,因为它总是返回相同的函数并将其中继到传递给它的最后一个函数。
我写过here。
答案 3 :(得分:0)
在您的示例中,expensiveCalc
中的函数useCallback
将在每个渲染器上运行,因为您要在每个渲染器的useCallback
下方直接调用记忆功能。
useCallback
将记住并返回实际功能,因此即使已记住该功能,只要您调用它,它仍将运行。
在该示例中,这实际上是正在发生的事情:
const calcCallback = () => expensiveCalc('useCallback');
const computedCallback = calcCallback();
您不应使用useCallback
。
如果可能,请将昂贵的函数移至react组件之外,并在外部执行它。 例如:
const calcResult = expensiveCalc('useCallback');
function App() {
如果由于某种原因不可能这样做,那么这里就是useMemo
所在的地方。
useMemo
将记住从函数返回的值,并在渲染之间保留该值,直到您的依赖项更改为止。
这意味着如果您不想在每个渲染器上运行昂贵的功能而只想要该值,则可以将其移出react组件的范围,或者使用useMemo
有关这两个钩子的更多详细信息,您可以阅读本文的更多信息:What is the difference between useMemo and useCallback?