Reputation: 15
So i'm trying to make a card guessing game and I need to set state multiple times in one clickHandler, but everytime it just uses the previous state because state is asynchronous and it doesn't have enough time to update. How can I achieve something similar to async await in this event handler? SetGame is my setState.
const clickHandler = (e) => {
let copy = [...game.pictures];
shuffle(copy);
setGame((prevState) => {
return { ...prevState, pictures: copy };
});
let clickedId = [...game.clickedPics];
if (!clickedId.includes(e.target.id)) {
setGame((prevState) => {
return { ...prevState, currentScore: game.currentScore + 1 };
});
if (game.highScore < game.currentScore) {
setGame((prevState) => {
return { ...prevState, highScore: game.currentScore };
});
}
clickedId.push(e.target.id);
setGame((prevState) => {
return { ...prevState, clickedPics: clickedId };
});
console.log(game.clickedPics);
} else {
setGame((prevState) => {
return { ...prevState, currentScore: 0 };
});
clickedId = [];
setGame((prevState) => {
return { ...prevState, clickedPics: clickedId };
});
}
};
Upvotes: 1
Views: 36
Reputation: 2979
Since, as you said, setState
is an async operation, you have to create your state object and only setGame
once in the end. Try this:
let copy = [...game.pictures];
const stateCopy = { ...game } // or whatever name your state is here
shuffle(copy);
stateCopy.pictures = copy;
let clickedId = [...game.clickedPics];
if (!clickedId.includes(e.target.id)) {
stateCopy.currentScore = game.currentScore + 1;
if (game.highScore < game.currentScore) {
stateCopy.highScore = game.currentScore;
}
clickedId.push(e.target.id);
stateCopy.clickedPics = clickedId;
console.log(game.clickedPics);
} else {
stateCopy.currentScore = 0;
clickedId = [];
stateCopy.clickedPics = clickedId;
}
setGame(stateCopy);
};
Upvotes: 2