Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should I include setState in useCallback's array of dependencies?

Tags:

    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?

like image 262
alanhchoi Avatar asked Apr 18 '19 01:04

alanhchoi


People also ask

Does useCallback need a dependency array?

useCallback also takes its own dependency array, which you can use to pass any variables that the function depends on. For example, let's say that the component actually takes in a url prop, which is used in the API request.

What are dependencies in useCallback?

The useCallback hook is used when you have a component in which the child is rerendering again and again without need. Pass an inline callback and an array of dependencies. useCallback will return a memoized version of the callback that only changes if one of the dependencies has changed.

What is an array of dependencies in useEffect useCallback?

Dependency arrays are a concept that is tightly coupled to hooks in React (thus also to function components). Some hooks, like useEffect and useCallback have 2 arguments. The first one is a callback (a function), and the second one is the dependency array. It takes the form of an array of variables.

Should I use useCallback or useMemo?

With useCallback you can define a function that has referential equality between renders. You can use useMemo to calculate a value that has referential equality between renders.


2 Answers

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.

like image 96
cbdeveloper Avatar answered Nov 29 '22 11:11

cbdeveloper


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.

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);   },   [setActive], // or just [] is okay? );  

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 );  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?

like image 27
AncientSwordRage Avatar answered Nov 29 '22 09:11

AncientSwordRage