Question

Should I wrap every prop with useCallback or useMemo, when to use this hooks?

With react hooks now available should I in case of functional components wrap every function passed with props with useCallback and every other props value with useMemo?

Also having custom function inside my component dependent on any props value should I wrap it with useCallback?

What are good practices to decide which props or const values from component wrap with this hooks ?

If this improves performance why not to do it at all times ?

Lets consider custom button where we wrap click handler and add custom logic

function ExampleCustomButton({ onClick }) {
  const handleClick = useCallback(
    (event) => {
      if (typeof onClick === 'function') {
        onClick(event);
      }

      // do custom stuff

    },
    [onClick]
  );

  return <Button onClick={handleClick} />;
}

Lets consider custom button where we wrap click handler and add custom logic on condition

function ExampleCustomButton({ someBool }) {
  const handleClick = useCallback(
    (event) => {
      if (someBool) {
        // do custom stuff
      }
    },
    [someBool]
  );

  return <Button onClick={handleClick} />;
}

Should i in this two cases wrap my handler with useCallback ?

Similar case with use memo.

function ExampleCustomButton({ someBool }) {
  const memoizedSomeBool = useMemo(() => someBool, [someBool])
  const handleClick = useCallback(
    (event) => {
      if (memoizedSomeBool) {
        // do custom stuff
      }
    },
    [memoizedSomeBool]
  );

  return <Button onClick={handleClick} />;
}

In this example I even pass memoized value to useCallback.

Another case what if in the component tree many components memoize same value ? How does this impact performance ?

 46  34079  46
1 Jan 1970

Solution

 50

Not worth it, for multiple reasons:

  1. Even official docs say you should do it only when necessary.
  2. Keep in mind that premature optimization is the root of all evil :)
  3. It makes DX (developer experience) far worse: it's harder to read; harder to write; harder to refactor.
  4. When dealing with primitives (like in your example) memoizing costs more CPU power than not doing it. A primitive value doesn't have a concept of references, so there's nothing to memoize in them. On the other hand, memoization itself (as any other hook) does require some tiny processing, nothing is for free. Even though it's tiny, it's still more than nothing (compared to just passing a primitive through), so you'd shoot your own foot with this approach.

To put all together - you'd waste more time typing all the hooks than a user would gain on having them in the application if you want to put them everywhere. The good old rule applies: Measure, then optimize.

2019-03-27

Solution

 24

I agree with the principles proposed by @jalooc

To give some more insight about the exhibited use cases in the OP, here is my advice:

Expensive children renders

function Component() {
  const callback = useCallback(() => { dostuff }, [deps])

  return <Child prop={callback} />
}

The above makes sense if Child is a very expensive component to render. As such, it is probably exported like so:

function Child() { 
   ...this takes significant CPU... 
}

// Export as a pure component
export default React.memo(Child)

Expensive computations

function Component({ foo }) {
  // This very expensive computation will only run when it's input (foo)
  // changes, allowing Component to re-render without performance issues
  const bar = useMemo(() => {
     ... something very complicated with `foo` ...
  }, [foo])

  return <div>{bar}</div>
}

Conclusion

  1. Do what makes sense or that have measured bad performance
  2. A function declaration inside a component changes at each render. If this causes derived expensive computations, memoize it (useCallback) or move it outside the scope.
  3. If a component itself is expensive to render, make it pure with React.memo, with the help of #2 if necessary
  4. If something IS itself expensive to re-compute, memoize it (useMemo)
  5. Do what makes sense or that have measured bad performance
2019-03-29