D
D
dmitry-toster2020-07-01 00:07:37
JavaScript
dmitry-toster, 2020-07-01 00:07:37

How to properly use useCallback in React?

I'm trying to optimize inline functions, i.e. such a notation

export default function({data, doSomething}) {
  return (
    <>
      {data.map(el => {
        <div onClick={() => doSomething(el.id)}>	
      })}
    </>
  )	
}

I change it to this:
export default function({data, doSomething}) {
  const handleClick = useCallback(id => doSomething(id), []);

  return (
    <>
      {data.map(el => {
        <div onClick={() => handleClick(el.id)}>	
      })}
    </>
  )	
}

and I get an error:
Uncaught Invariant Violation: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.

I also tried to pass it to the dependency array data, the result is the same

Answer the question

In order to leave comments, you need to log in

2 answer(s)
8
8XL, 2020-07-01
@dmitry-toster

function Child ({data, sayHi}) {

  const handleClick = useCallback(el => {
    sayHi(el)
  }, [])

  return (
    <div className="App">
      {data.map(el=>
        <div
          onClick={()=>handleClick(el)}
        >
          {el}
        </div>
      )}
    </div>
  )
}

export default function App() {
  const data = [1,2,3,4]
  
  const sayHi = (el) => {
    console.log('Hi '+ el)
  } 

  return (
    <Child data={data} sayHi={sayHi} />
  )
}

You are cheating, there is no mistake in the hook.
In fact, doSomething( ) causes an error, in which, most likely, setState( ) is called, which causes rendering and so on ad infinitum, which does not allow rendering.

D
Daniil, 2020-07-01
@TchernyavskD

Specifically in your example - useCallback is not needed. Read it in the documentation.
You call the `useCallback` function on each render and pass your handler to it. When you do this, you are forced to create a function before passing it to useCallback
Memoization works here so that if your deps have not changed, useCallback will ignore the new argument and return the old handler to you

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question