gpt4 book ai didi

reactjs - useCallback 和 useMemo 在实践中有何区别?

转载 作者:行者123 更新时间:2023-12-03 12:55:09 25 4
gpt4 key购买 nike

也许我误解了一些东西,但是每次重新渲染发生时 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>

最佳答案

TL;DR;

  • useMemo就是记住函数调用之间和渲染之间的计算结果
  • useCallback是在渲染之间记住回调本身(引用相等)
  • useRef是在渲染之间保留数据(更新不会触发重新渲染)
  • useState是在渲染之间保留数据(更新将触发重新渲染)

长版:

useMemo专注于避免繁重的计算。

useCallback专注于不同的事情:它修复了像 onClick={() => { doSomething(...); } 这样的内联事件处理程序时的性能问题。原因PureComponent子级重新渲染(因为函数表达式每次引用都不同)

这就是说,useCallback更接近useRef ,而不是一种内存计算结果的方法。

调查docs我确实同意它看起来很困惑。

useCallback will return a memoized version of the callback that only changes if one of the inputs has changed. This is useful when passing callbacks to optimized child components that rely on reference equality to prevent unnecessary renders (e.g. shouldComponentUpdate).

示例

假设我们有一个PureComponent基子<Pure />仅当其 props 时才会重新渲染已更改。

每次重新渲染父级时,此代码都会重新渲染子级 - 因为每次内联函数的引用都不同:

function Parent({ ... }) {
const [a, setA] = useState(0);
...
return (
...
<Pure onChange={() => { doSomething(a); }} />
);
}

我们可以在 useCallback 的帮助下处理这个问题:

function Parent({ ... }) {
const [a, setA] = useState(0);
const onPureChange = useCallback(() => {doSomething(a);}, []);
...
return (
...
<Pure onChange={onPureChange} />
);
}

但是一次a改变后我们发现onPureChange我们创建的处理函数——React 为我们记住了——仍然指向旧的 a值(value)!我们遇到的是错误而不是性能问题!这是因为onPureChange使用闭包来访问a变量,当 onPureChange 时捕获被宣布。为了解决这个问题,我们需要让 React 知道在哪里放置 onPureChange并重新创建/记住(内存)指向正确数据的新版本。我们通过添加a来做到这一点作为 `useCallback 的第二个参数中的依赖:

const [a, setA] = useState(0);
const onPureChange = useCallback(() => {doSomething(a);}, [a]);

现在,如果a更改后,React 重新渲染 <Parent> 。在重新渲染期间,它会看到 onPureChange 的依赖项不同,需要重新创建/内存新版本的回调。这被传递到 <Pure>由于它的引用不同,<Pure>也被重新渲染。终于一切正常了!

注意不仅仅是PureComponent/React.memo ,当在 useEffect 中使用某些东西作为依赖项时,引用相等可能至关重要。 .

关于reactjs - useCallback 和 useMemo 在实践中有何区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54963248/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com