I want to make a card memory game. When two cards are flipped isClickable needs to change to false in order for other cards to be unclickable, and that's what happens. But, at the end isClickable is always set to true. I don't know why. Here's my code.
const Card = ({ number, flipped, flipHandler, index }) => {
return (
<div
className={flipped ? "card disabled" : "card"}
data-index={index}
onClick={flipHandler}
>
{flipped ? number : "FLIP ME"}
</div>
);
};
const Game = () => {
const [cardState, setCardState] = React.useState({
gameState,
isClickable: true
});
function handleClick(e) {
let newGameState = cardState.gameState.map((card, index) => {
if (index === e.target.dataset.index) {
card.isFlipped = !card.isFlipped;
}
return card;
});
setCardState({ ...cardState, gameState: newGameState });
if (checkGame(cardState.gameState)) {
setCardState({ ...cardState, isClickable: false });
setTimeout(() => {
let flippedCards = cardState.gameState.filter((card) => card.isFlipped);
if (flippedCards[0].number === flippedCards[1].number) {
const newGameState = cardState.gameState.filter(
(card) => card.number !== flippedCards[0].number
);
setCardState({ ...cardState, gameState: newGameState });
} else {
const newGameState = cardState.gameState.map((card) => {
return { ...card, isFlipped: false };
});
setCardState({ ...cardState, gameState: newGameState });
}
}, 1000);
}
}
let cards = cardState.gameState.map((card, index) => {
return (
<Card
number={card.number}
flipHandler={
cardState.isClickable
? handleClick
: function () {
return false;
}
}
flipped={card.isFlipped}
index={index}
/>
);
});
return <>{cards}</>;
};
CodePudding user response:
To explain why it doesn't work now.
Simplified example:
// this runs as expected
setCardState({...cardState, isClickable: false});
setTimeout(()=>{
// now after 1000 ms your anonymous function see the old `cardState`
// that's because react creates new objects every time a component renders
setCardState({...cardState, gameState: newGameState});
// using this instead gives access to the newest state every time
setCardState(cardState => {...cardState, gameState: newGameState});
}, 1000);