50
    const [active, setActive] = useState(false);

    const onActiveChanged = useCallback(
      isActive => () => {
        // do something
        setActive(isActive);
      },
      [setActive], // or just [] is okay?
    );

When using useState and useCallback (or useMemo) together, should I include setState in the array of dependencies?

3
  • @AngelSalazar The updater method from useState isn't memoized or doesn't persist the same reference? Commented Apr 18, 2019 at 3:10
  • 6
    my bad, according to the docs "React guarantees that setState function identity is stable and won’t change on re-renders. This is why it’s safe to omit from the useEffect or useCallback dependency list." Commented Apr 18, 2019 at 3:17
  • @AngelSalazar Thanks for confirmation! I also found that part in github.com/reactjs/reactjs.org/blob/master/content/docs/… So just passing an empty array must be okay. You can leave it as an answer to this question or I'll post an answer to my own question. Commented Apr 18, 2019 at 3:23

3 Answers 3

71

The recommendation for that is also on React Docs - Hooks API Reference.

The setState function is used to update the state. It accepts a new state value and enqueues a re-render of the component.

setState(newState);

During subsequent re-renders, the first value returned by useState will always be the most recent state after applying updates.

Note

React guarantees that setState function identity is stable and won’t change on re-renders. This is why it’s safe to omit from the useEffect or useCallback dependency list.

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

2 Comments

This answer is slightly obsolete now since it refers to obsolete docs. The new docs actually do not promise that the setter will be stable, but maybe that's just an oversight?
That's still valid. It's mentioned on the useCallback page: react.dev/reference/react/…
3

The purpose of useCallback as you rightly hinted is to memoise:

useCallback(fn, deps) is equivalent to useMemo(() => fn, deps).

And as for what useMemo is intended for:

You may rely on useMemo as a performance optimization, not as a semantic guarantee.

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

But as a rule, useState is stable between renders (i.e. pre-memoised), so you should not need to memoise it again, so it can be safely omited from dependency callbacks.

The question then comes, is your 'do something' below an expensive calculation? It shouldn't be to onerous to make use of useCallback, but it could well be boilerplate code you don't need, and could make almost direct use of your setActive function.

const [active, setActive] = useState(false);

const onActiveChanged = useCallback(
  isActive => () => {
    // do something
    setActive(isActive);
  },
  [],
);

Another way to prevent unnecessary dependencies, in your useCallback and other hooks, is to make use of functional updates. The result being that you can have these:

const [active, setActive] = useState(false);
const [expensiveCalc, setExpensiveCalc] = useState(false);

const onExpensiveCalc = useCallback(
  expensiveInput => () => {
    const newState = doExpensiveCalc(expensiveInput);
    expensiveCalc(newState);
  },
  [setActive], // here for completeness only
);

return (<>
  // expensive calculation
  <button onClick={onExpensiveCalc}>Do lengthy calculation</button>
  // cheap calculation, using functional updates
  <button onClick={() => setActive(prevBoolean => !prevBoolean)}>Cheap Set Active</button>
</>)


Do note, that there's a little nuance to how set state works in an onClick, and you should make use of an arrow function, so your setActive is run on click, not render. This is shown in the second answer above, but without explanation.

See also: What is useState() in React?

Comments

-2

you don't need to pass the setActive as it will never change, as it is react setState function not a state. so you can pass an empty array instead, since passing setActive won't change the behaviour of the useCallback anyways.

3 Comments

1. in general function references can change like any object reference. 2. setState is stable, but other answers already stated that.
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
@Martin yes, they can change, but not in the case of setActive, as it will remain same throughout the code rerenders

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.