0

I am not really sure when we should avoid using useCallback, if there is any harm (memory reallocation). For example lets say I have a component with two props, {onSave, onClose} and one state viewName. is bellow handler function will be optimized with these dependencies?

  const handleSaveView = useCallback(() => {
    onSaveView(viewName, selectedViewList);
    onClose();
  }, [onSaveView, onClose, viewName]);
1
  • The question you've asked requires knowing more about your app than what you've shown. Please provide a minimal, reproducible example. Commented May 25, 2022 at 7:29

2 Answers 2

2

useCallback saves a function you pass to it and, in the future, returns that function instead of the new one if any of the values in the dependency array change.

This comes at a cost, mostly in the tests of the dependency array and, most of the time, it isn't worth using. It's a very tempting tool for premature optimization.

There are times when that cost is worth paying, such as when the function has an internal state or it is a dependency of another hook (so recreating the function would trigger the other hook to re-run).

Dmitri Pavlutin's "Your Guide to React.useCallback()" covers this in more depth.

Sign up to request clarification or add additional context in comments.

Comments

1

In short, yes, but make sure you also memoize (e.g., via useCallback) your onSave and onClose handlers where you create them, if you create them in render cycle (as you do with handleSaveView). Don’t forget to pass selectedViewList as dependency, too.

Why use React memoization hooks

There are two reasons to React memoization hooks (of which useCallback is one) for: A) reference equality, and B) computation caching. Your example is about reference equality, so we’ll talk only about that.

Why memoize for reference equality

To avoid extra re-renders (i.e., rendering a component again even if nothing changed).

React will want to render whenever a prop changes, and strict equality operator is used when checking whether a prop changed. With JavaScript’s strict equality operator, a non-primitive value is different every time you instantiate it, even if you instantiate it the exact same way.

This includes traditional objects, functions, arrays:

{ foo: 'bar' } !== { foo: 'bar' }
function a() { return true } !== function a() { return true }
[1, 2, 3] !== [1, 2, 3]

Therefore, if you 1) create a non-primitive value { foo: 'bar' } within render cycle (i.e., in the body of a React function component) and 2) pass this value as prop to another component, then you need a way of telling React that { foo: 'bar' } is the same as { foo: 'bar' } if you want to avoid unnecessary renders of that component.

How hooks ensure reference equality

React’s hooks allow you to declare that “this non-primitive value is the same if all of those other values (dependencies) are the same”. But again, React uses strict equality to check whether dependencies are the same.

Memoizing is useless if you don’t ensure reference equality of dependencies

Everything is fine if your dependencies are primitive values (numbers, strings, null, and so on).

However, in case of this question, I assume onSave and onClose are functions. Non-primitive values. Which means, if you declare them in some component’s render cycle, they are re-created every render. Therefore, unless you also memoize them, your memoization will be completely pointless, your handleSaveView will be new every time, and if you pass it to another component it may be re-rendered even if you don’t expect it.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.