kentcdodds / ama

Ask me anything!
https://github.com/kentcdodds/ama/issues?q=is%3Aissue+is%3Aclosed
685 stars 75 forks source link

Question regarding your useMemo & useCallback blog #850

Closed Atif252 closed 4 years ago

Atif252 commented 4 years ago

I got really confused after reading your second solution in the When to useMemo and useCallback blog's Dependencies List section.

function Foo({bar, baz}) {
  React.useEffect(() => {
    const options = {bar, baz}
    buzz(options)
  }, [bar, baz])
  return <div>foobar</div>
}

function Blub() {
  const bar = React.useCallback(() => {}, [])
  const baz = React.useMemo(() => [1, 2, 3], [])
  return <Foo bar={bar} baz={baz} />
}

React should not re-compute those functions on re-render because props are unchanged and as mentioned in Optimize React re-renders , React automatically provides us optimization by not re-rendering / re-computing those pieces of code which are coming from props.

I also tested it and it turns out that we don't need to wrap our non-primitives when we are sending them as props to other components, React will optimize them for us. And thus the below code will work just fine and will not fire effects when non-primitives are passed as props

function Foo({bar, baz}) {
  React.useEffect(() => {
    const options = {bar, baz}
    buzz(options)
  }, [bar, baz])
  return <div>foobar</div>
}

function Blub() {
  const bar = () => {};
  const baz = [1, 2, 3];
  return <Foo bar={bar} baz={baz} />
}
kentcdodds commented 4 years ago

And thus the below code will work just fine and will not fire effects when non-primitives are passed as props

This is incorrect. I'd suggest you do some more testing. Feel free to provide a codesandbox demonstrating what you think is working and I'll alter it to show you that it is not :)

Atif252 commented 4 years ago

Kindly have a look at this and correct me if I am wrong. I would really appreciate that. CodeSandbox

kentcdodds commented 4 years ago

Here you go: https://codesandbox.io/s/test252-unpzy

In your version the state change was happening in the useEffect component, so the values in the dependency array were unchanged.

In my version I moved it to the parent component and you'll notice that the effect is called every render because those values are created brand new for every change.

Atif252 commented 4 years ago

Thanks for your help.