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?
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"/>
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>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With