在没有 React.memo 的情况下使用 useCallback 有什么好处吗?

Rav*_*ary 6 javascript reactjs react-hooks usecallback

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

Gun*_*son 1

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

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

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

然而,通过配对,您可以绕过重新渲染父级内部定义的组件。

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

例子

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'));
Run Code Online (Sandbox Code Playgroud)