Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the difference between setCount(prev => prev + 1) and setCount(count + 1)?

I am reading an example of React hooks. I find they write

setCount(count + 1)

But I usually wrote like this

setCount(prev => prev + 1)

Is there any difference? Which one is better?

like image 316
Doraemon Avatar asked Oct 23 '25 16:10

Doraemon


2 Answers

There is a difference, in the first, the count will be based on the current value at the time that that render occurred due to the closure in the function.

The second would always use the latest value for the increment.

Because closures are a complicated topic, here's some examples. The first shows the main difference between the two.

The second example shows several ways that will allow things to work properly with closures and effects/hooks

const { useState, useEffect } = React;
function Example(){
const [count1, setCount1] = useState(0);
useEffect(()=>{
  setCount1(count1 + 1);
  setCount1(count1 + 1);
  setCount1(count1 + 1);
},[])

const [count2, setCount2] = useState(0);
useEffect(()=>{
  setCount2(prev=> prev + 1);
  setCount2(prev=> prev + 1);
  setCount2(prev=> prev + 1);
},[])
return <div>
Both count1 and count2 have had 3 increments.
<br/>
count1 stays at 1 because the count1 variable in the useEffect isn't change due to the closure in the arrow function in the useEffect
<br/>
Current count1: {count1}
<br/>
Current count2: {count2}
</div>
}
ReactDOM.render(<Example/>,document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<div id="root"/>

const { useState, useEffect, useRef } = React;
function Example(){
const [count1, setCount1] = useState(0);
const [count2, setCount2] = useState(0);
const [count3, setCount3] = useState(0);

const count3Ref = useRef(count3);
count3Ref.current = count3;

useEffect(()=>{
  const id = setInterval(()=>{
  setCount1(count1+1);
  setCount2(prev=>prev+1);
  setCount3(count3Ref.current+1);
  },300)
  return ()=>{clearInterval(id)}
},[])

const [count4, setCount4] = useState(0);
useEffect(()=>{
  const id = setTimeout(()=>{
  setCount4(count4+1);
  },300)
  return ()=>{clearTimeout(id)}
},[count4])
return <div>
All of the counts theoretically increment every 300ms
<br/>
<br/>
count1 stays at 1 because the count1 variable in the useEffect isn't change due to the closure in the arrow function in the useEffect
<br/>

Current count1: {count1}
<hr/>
count2 uses the functional version of setCount2 so it always uses the latest version and will update properly
<br/>
Current count2: {count2}
<hr/>
count3 increments because refs are mutable by nature and allow us to bypass the closure.
<br/>
Current count3: {count3}
<hr/>
Another possiblity: count4 increments because we properly use the dependency array and force the useEffect to re-run every time count4 changes.
<br/>
Current count4: {count4}

</div>
}
ReactDOM.render(<Example/>,document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<div id="root"/>
like image 50
Zachary Haber Avatar answered Oct 25 '25 08:10

Zachary Haber


Well, It depends on the situation.

If you want to update the state whose values depend on the previous state then you should use below.

setCount(prev => prev + 1);

This will update the state to the new state.

If you use this like below, then it will update the count for one but not two times because setState is asynchronous in nature.

setCount(count + 1);
setCount(count + 1);

But if you do this

setCount(count => count + 1);
setCount(count => count + 1);

Then it will update the state two times as we are updating the state from the previous state.

const {useState} = React;

const Example = () => {

  const [count, setCount] = useState(0);

  const handleClick = () => {
    setCount(count => count + 1);
    setCount(count => count + 1);
  }

  return ( 
  <div>
    <p> {count} </p> 
    <button onClick = {handleClick}> Add by 2 </button>  
    </div>
  );
};

ReactDOM.render( 
  <Example />, document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react"></div>
like image 31
Subrato Pattanaik Avatar answered Oct 25 '25 07:10

Subrato Pattanaik