Elie Asmar
Elie Asmar

Reputation: 3165

useCallback() dependency array vs constant-reference callback

As per React official documentation, if a component new state is computed using the previous state, one can pass a function to setState. The function will receive the previous value, and return an updated value.

Consider the following code snippet example:

const [counter, setCounter] = useState(0);
const btnClick = useCallback(() => setCounter(counter+1), [counter]); //(1)
const btnClick = useCallback(() => setCounter(previous => previous+1), []);//(2)

btnClick is passed as a callback function for the 'onClick' event of a rendered button.

In (1), the btnClick function reference is updated each time the counter state variable is modified.

In (2), the btnClick function reference is created during the first render cycle and is cached for the rest of the component lifetime; at this level, the state update function will receive the previous state value and return an updated value.

At this level, I have 2 questions:

1- As a good practice, should I opt for (1) or (2)? And are there any advantages for using (1) instead of (2)?

2- Does (2) apply to both primitive and reference types? (check below, I switched the state from being an Integer to an Object)

const [counter, setCounter] = useState({cntr:1});
const btnClick = useCallback(() => setCounter({...counter,cntr:counter.cntr+1}), [counter]); //(1)
const btnClick = useCallback(() => setCounter(previous => return {...previous ,cntr:previous.cntr+1}), []);//(2)

Does "previous" in (2) still reference the previous state value or does it refer to a stale state that was cached during the component first render cycle?

Your help is appreciated.

Upvotes: 3

Views: 600

Answers (1)

Egor Pashko
Egor Pashko

Reputation: 354

So, it is a deep question, let's try to explain how it works.

  1. useCallback just promise you that btnClick will not reinitialize. This does not related to useState and body of function at all.
  2. In react community we do not have any good practices on this point. The difference is when you call setState react promise you that sometimes value will be updated. For example:
setValue(1);
setValue(2);
setValue(3); 

It does not mean react will update the state three times. React can combine it to one update and set just last value.

  1. Pass function as a argument to setState
const myFunc = (oldValue) => ({}) 
useValue(myFunc)

it means that react sees you pass function then all useValue will be called immediately and after useValue(myFunc) will be called. Developers need it to work with last data which is placed in the state.

Does "previous" in (2) still reference the previous state value or does it refer to a stale state that was cached during the component first render cycle?

So, as a result of the question previous in setState will be recent value from state.

Upvotes: 2

Related Questions