I am creating 50 buttons which on click should set the useState value to the current button number (array index+1). But I realized that I have to click a button twice to get the current value (array index+1). The first click always gets the previously clicked button value. e.g. When I clicked button 1 for the first time, I get nothing, when I clicked button 2 I get 1, when I clicked button 3 I get 2. Thank you.
Here is the code
const [theValue, setTheValue] = useState({first: 1});
const [disableNext, setDisableNext] = useState(false);
const [disablePrev, setDisablePrev] = useState(true);
<div className="flex flex-row">
{disablePrev ? <div className="flex flex-1 justify-start">
<button type="button" className="btn bg-gray-300 text-gray-400 m-10" disabled>Previous</button></div>
: <div className="flex flex-1 justify-start">
<button type="button" className="btn bg-jamb-light-green text-white m-10 hover:bg-green-400" onClick={prevButton}>Previous</button></div>}
{disableNext ? <div className="flex flex-1 justify-end">
<button type="button" className="btn bg-gray-300 text-gray-400 m-10" disabled>Next</button></div>
: <div className="flex flex-1 justify-end">
<button type="button" className="btn bg-jamb-light-green text-white m-10 hover:bg-green-400" onClick={nextButton}>Next</button></div> }
</div>
<div>
{[...Array(50)].map((item, index) => {
return (
<button key={index} className={(index+1 === theValue.first) ? "w-10 h-10 p-2 m-0.5 rounded-full bg-green-500 text-white" : "w-10 p-2 m-0.5 rounded-full bg-red-300 hover:bg-green-400 hover:text-white"}
onClick={
() => {
if(theValue.first === 1){
setDisablePrev(true);
}else if((theValue.first > 1) && (theValue.first < 49)){
setDisablePrev(false);
}
if(theValue.first === 50){
setDisableNext(true);
}else if(theValue.first < 50 && theValue.first > 1){
setDisableNext(false);
}
setTheValue({...theValue, first: index+1})
}
}>{index+1}</button>
)
})}
</div>
That is because the state is set on the next render. To update the state by 1 you could do:
const [theValue, setTheValue] = useState({first: 1});
<div>
{[...Array(50)].map((item) =>(
<button key={index} className={(index+1 === theValue.first) ? "w-10 h-10 p-2 m-0.5 rounded-full bg-green-500 text-white" : "w-10 p-2 m-0.5 rounded-full bg-red-300 hover:bg-green-400 hover:text-white"}
onClick={
() => {
setTheValue(currentStateValue => {...currentStateValue, first: currentStateValue.first+1})
}
}>{index+1}</button>
)
)}
</div>
Firstly, there is typo in your second if condition, theValue.firts. Coming to your issue, when you update a state inside a function, the updated state is not immediately accessible inside the same function. You only have access to the previous state value. So let's say, the current state value is 9 and when you click button number 10, you are updating the state value to 10 and at the same time console logging the value of theValue.first whose value is still 9 currently since it doesn't have access to the updated state value of 10. Now if you click the same button number again, it will display 10 but it doesn't mean it is the updated state value, it is the value of state that you previously set(which is 10) when you clicked the button. That's what is going on there. However, you will be able to access the latest updated state value inside the render div inside the paragraph as I have added for demo below. Going with your question, the state value is updated correctly. It's just that console logging from the same function makes you feel otherwise.
const [theValue, setTheValue] = useState({
first: 1
});
<div> {
[...Array(50)].map((item, index) => {
return ( <
button key = {
index
}
className = {
(index + 1 === theValue.first) ? "w-10 h-10 p-2 m-0.5 rounded-full bg-green-500 text-white" : "w-10 p-2 m-0.5 rounded-full bg-red-300 hover:bg-green-400 hover:text-white"
}
onClick = {
() => {
if (theValue.first === 1) {
console.log(theValue.first);
} else if (theValue.first > 1) {
console.log(theValue.first);
}
if (theValue.first === 50) {
console.log(theValue.first);
} else if (theValue.first < 50) {
console.log(theValue.first);
}
setTheValue({ ...theValue,
first: index + 1
})
}
} > {
index + 1
} < /button>
)
})
}
<p>{theValue.first}</p> // access to updated state value
</div>