【问题标题】:is there any benefit of using useCallback without React.memo?在没有 React.memo 的情况下使用 useCallback 有什么好处吗?
【发布时间】:2020-04-27 00:34:42
【问题描述】:

根据我从 React 文档和 Web 上的其他材料中了解到的情况,useCallback 用于通过确保将回调的记忆版本传递给子组件来避免重新渲染子组件,因此子组件的引用属性保持不变。但只有当我在子组件上使用 React.memo 时,所有这些才有效。如果没有 React.memo,子组件无论如何都会重新渲染。我的问题是 useCallback 在这种情况下有什么用,即没有 React.memo 应用于子组件。 useCallback 的其他好处是什么?

【问题讨论】:

  • 检查 useCallback 部分dev.to/dinhhuyams/…
  • 这个链接也谈到了同样的事情。我的问题是:除了避免重新渲染子组件之外,还有其他 useCallback 用例吗?

标签: javascript reactjs react-hooks usecallback


【解决方案1】:

您可能还需要将函数传递给useEffect,而不是在每次渲染时更改useEffect

例如:

import { useCallback, useEffect } from "react";

function useExample() {
  function fn() {
    console.log("a function");
  }
  const callback = useCallback(fn, []);

  useEffect(() => {
    callback();
  }, [callback]);
}

Real-world example with useDebounce:

【讨论】:

    【解决方案2】:

    React.memo 确保当 props 进入组件时执行浅比较,并在它们相等时跳过组件的渲染。

    给定一个子组件 Cell: 当应用于在另一个父组件的渲染期间创建的功能组件时,将在每个渲染上创建一个新的 Cell 组件。这个新的 Cell 组件将始终对其 props 进行浅层比较,但它会在其父级的每次渲染时重新渲染。

    但是,如果它的依赖数组在父重新渲染期间没有改变,useCallback 将记住这个函数回调 Cell。 单独一个函数组件 Cell 包裹在 useCallback 中时,它总是会在收到 props 时重新渲染,这将在其父级的每次渲染时发生。 然而不同的是,如果组件本身被重新创建,它的整个子树会被重新渲染,就像单独使用 React.memo 时的情况一样。

    但是,如果将它们配对在一起,您可以绕过在父级内部定义的重新渲染组件。

    您会注意到,当尝试拖动 Memoized 单元格时,未包含在 useCallback 中的单元格不会发生拖动。这是因为您尝试拖动的原始元素在其父元素重新渲染时被重新创建为新实例。 这个概念有更详细的解释here

    示例

    const { useCallback, useState, useRef } = React;
    
    function App() {
      const [state, setState] = useState(false);
      const [title, setTitle] = useState("");
    
      const Cell = useCallback(({ title }) => {
        console.log(`${title} rendering`);
    
        function onDragStart() {
          setState(true);
        }
        function onDragEnd() {
          setState(false);
        }
    
        return (
          <div draggable onDragStart={onDragStart} onDragEnd={onDragEnd}>
            Drag {title}
          </div>
        );
      }, []);
    
      const MemoizedCell = React.memo(({ title }) => {
        console.log(`${title} rendering`);
    
        function onDragStart() {
          setState(true);
        }
        function onDragEnd() {
          setState(false);
        }
    
        return (
          <div draggable onDragStart={onDragStart} onDragEnd={onDragEnd}>
            Drag {title}
          </div>
        );
      });
    
      const MemoizedCallbackCell = useCallback(
        React.memo(({ title }) => {
          console.log(`${title} rendering`);
    
          function onDragStart() {
            setState(true);
          }
          function onDragEnd() {
            setState(false);
          }
    
          return (
            <div draggable onDragStart={onDragStart} onDragEnd={onDragEnd}>
              Drag {title}
              <button onClick={() => setTitle(" Updated")}>Change Title</button>
            </div>
          );
        }),
        []
      );
    
      return (
        <div className="App">
          <Cell title="Cell" />
          <MemoizedCell title="Memoized Cell" />
          <MemoizedCallbackCell title={"Memoized Callback Cell" + title} />
          Is dragging {`${state}`}
          <br />
        </div>
      );
    }
    
    ReactDOM.render(<App />, document.getElementById('root'));

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-12-15
      • 1970-01-01
      • 1970-01-01
      • 2023-01-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多