【问题标题】:What's the difference between useCallback and useMemouseCallback 和 useMemo 有什么区别
【发布时间】:2020-06-01 14:25:23
【问题描述】:

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

我传递了输入 - 作为 useCallback 的第二个参数 - 不可更改的常量 - 但返回的记忆回调仍然在每次渲染时运行我昂贵的计算(我很确定 - 你可以在 sn-p 中自己检查下面)。

我已将 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>

【问题讨论】:

    标签: reactjs react-hooks


    【解决方案1】:

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

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

    【讨论】:

      【解决方案2】:

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

      useCallback() 防止在每次重新渲染时创建函数的新实例(我的意思是重新定义函数),因此如果我们将函数作为道具传递给子组件,则可以防止重新渲染子组件

      【讨论】:

        【解决方案3】:

        现在 (25.05.2020),useCallbackuseMemo 可以互换使用:

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

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

        我写了here

        【讨论】:

          【解决方案4】:

          在您的示例中,useCallback 中的函数 expensiveCalc 将在每次渲染时运行,因为您在每次渲染时直接在 useCallback 下方调用 memoized 函数。

          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?

          【讨论】:

            猜你喜欢
            • 2019-07-24
            • 2019-11-18
            • 1970-01-01
            • 2022-12-18
            • 2022-12-15
            • 2022-12-23
            • 2023-03-25
            • 2019-11-16
            相关资源
            最近更新 更多