简体   繁体   中英

is there any benefit of using useCallback without React.memo?

From what i understood from React documentation and other material across web, useCallback is used to avoid re-rendering of child component by ensuring that memoized version of callback is passed to it, thus referentially props remain same for child component. But all this is valid only if I am using React.memo on child component. Without React.memo, child component would re-render anyways. My question is what use is useCallback in this case ie without React.memo applied to child component. What are the other benefits of useCallback?

React.memo ensures that a shallow comparison is performed when props enter a component and skips rendering of the component when they are equal.

Given a child component Cell: When applied to a function component that is created during the render of another, parent component, a new Cell component will be created on each render. This new Cell component will always make shallow comparisons on its props but it will be re-rendered on every render of its parent.

useCallback will however memoize this function callback Cell if it's dependency array does not change during a parent re-render. Alone a function component Cell wrapped in a useCallback will always re-render when it receives props, which will happen on every render of its parent. The difference however is that it's entire subtree is re-rendered if the component itself is recreated, as is the case when using React.memo by itself.

Paired together you can however get around re-rendering components defined inside of a parent.

As you will notice, when attempting to drag the Memoized cell, the one not wrapped in useCallback, no dragging happens. That is because the original element you attempt to drag is recreated as a new instance when it's parent re-renders. This concept is explained in more detail here

Example

 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'));

You might also need to pass a function to useEffect without changing useEffect on every render

For example:

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 :

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM