React卡片匹配游戏:点击卡片无法为choiceTwo赋值求助
React卡片匹配游戏选择状态赋值异常问题
我正在开发一款基于React的卡片匹配游戏,卡片通过data-keyMatch绑定数值。需求是:点击首张卡片将keyMatch值存入choiceOne状态;点击第二张卡片时,若choiceOne已有值则存入choiceTwo状态。
卡片元素导入自MatchingCard组件,点击事件在父组件中通过handleChoice函数绑定。我尝试将choiceOne、choiceTwo默认状态设为null或0,但点击卡片时始终仅能重复赋值choiceOne,choiceTwo从未被赋值。不过测试函数check的逻辑正常,相关代码如下:
父组件核心代码
// -----------------Matching Card Game Functionality -------------------- // -------------------------------------------------------------------------- // States const [doubledDeck, setDoubledDeck] = useState([]); const [shuffledDeck, setShuffledDeck] = useState([]); const [deckReady, setDeckReady] = useState([]); const [matchingGameActive, setMatchingGameActive] = useState(false); const [turns, setTurns] = useState(0); const [choiceOne, setChoiceOne] = useState(0); const [choiceTwo, setChoiceTwo] = useState(0); // 测试用函数,逻辑正常 const random = Math.floor(Math.random() * 10); const check = () => { choiceOne != 0 ? setChoiceTwo(random) : setChoiceOne(random); if (turns === 0) { setChoiceOne(random); setTurns((prevTurn) => prevTurn + 1); } if (turns === 1) { setChoiceTwo(random); setTurns(0); } }; // 生成双倍卡组 const doubleTheDeck = (deck: any) => { const FlashcardsEnglish = deck.map((card: { props: { children: { props: any }[] } }) => { return card.props.children[0].props; }); const FlashcardsJapanese = deck.map((card: { props: { children: { props: any }[] } }) => { return card.props.children[1].props; }); const joinedDeck = FlashcardsEnglish.concat(FlashcardsJapanese); setDoubledDeck(joinedDeck); }; // 洗牌函数 const shuffle = (deck: any[]) => { const shuffledCards = deck .sort(() => Math.random() - 0.5) .map((card) => ({ ...card, })); setShuffledDeck(shuffledCards); }; // 卡片点击处理函数 const handleChoice = (e: { target: { dataset: { keyMatch: any } } }) => { const parsed = parseInt(e.target.dataset.keyMatch); // 尝试1:用null作为默认状态 // choiceOne ? setChoiceTwo(parsed) : setChoiceOne(parsed); // 尝试2:用0作为默认状态 if (turns === 0) { setChoiceOne(parsed); setTurns((prevTurn) => prevTurn + 1); } if (turns === 1) { setChoiceTwo(parsed); setTurns(0); } }; console.log(choiceOne, choiceTwo); // 生成卡组JSX const finalDeck = shuffledDeck.map((card: { matchId: any; word: any }) => { const { matchId, word } = card; return ( <MatchingCards key={matchId + word[0]} matchId={matchId} word={word} handleChoice={handleChoice}></MatchingCards> ); }); // 开始游戏处理 const handleMatchingGameClick = () => { doubleTheDeck(cardsForMatchingGame); shuffle(doubledDeck); setDeckReady(finalDeck); setMatchingGameActive((prevState) => !prevState); }; // useEffect(() => {}, []); return ( <div> <div> <Header pageHeader={className} /> <div className="bg-white">choice 1: {choiceOne}</div> <div className="bg-white">choice 2: {choiceTwo}</div> <button onClick={check}>check</button> </div> <div className="flex items-center justify-between bg-slate-200 dark:bg-bd-1 p-4 "> <HomeButton /> <MatchingGameButton content={matchingGameActive ? "Back to Regular Deck" : "Go to Matching Game"} onClick={handleMatchingGameClick} /> <ToggleButton /> </div> <div className=" dark:bg-bd-1 p-10 bg-slate-200 gap-5 flex flex-col items-center justify-center sm:items-center sm:justify-center sm:grid sm:grid-cols-2 md:grid md:grid-cols-3 lg:grid-cols-4 " > {matchingGameActive ? deckReady : cards}; </div> </div> );
MatchingCards组件返回内容
return ( <div> <div> <Header pageHeader={className} /> <div className="bg-white">choice 1: {choiceOne}</div> <div className="bg-white">choice 2: {choiceTwo}</div> <button onClick={check}>check</button> </div> <div className="flex items-center justify-between bg-slate-200 dark:bg-bd-1 p-4 "> <HomeButton /> <MatchingGameButton content={matchingGameActive ? "Back to Regular Deck" : "Go to Matching Game"} onClick={handleMatchingGameClick} /> <ToggleButton /> </div> <div className=" dark:bg-bd-1 p-10 bg-slate-200 gap-5 flex flex-col items-center justify-center sm:items-center sm:justify-center sm:grid sm:grid-cols-2 md:grid md:grid-cols-3 lg:grid-cols-4 " > {matchingGameActive ? deckReady : cards}; </div> </div> );
问题原因及修复方案
1. React状态更新异步性导致turns判断失效
在handleChoice中直接使用turns值判断时,由于React状态更新是异步的,调用setTurns后当前函数上下文的turns不会立即更新,第二次点击时turns仍为0,因此始终执行setChoiceOne。
修复代码:
const handleChoice = (e: React.MouseEvent<HTMLDivElement>) => { const parsed = parseInt(e.currentTarget.dataset.keyMatch!); setTurns(prevTurns => { if (prevTurns === 0) { setChoiceOne(parsed); return 1; } else { setChoiceTwo(parsed); return 0; } }); };
2. MatchingCards组件逻辑错误
你提供的MatchingCards组件完全复制了父组件的渲染内容,导致状态和事件逻辑混乱。正确的组件应仅负责渲染单张卡片,并将data-keyMatch绑定到自身元素上。
修正后的MatchingCards组件:
type MatchingCardsProps = { matchId: number; word: string[]; handleChoice: (e: React.MouseEvent<HTMLDivElement>) => void; }; const MatchingCards = ({ matchId, word, handleChoice }: MatchingCardsProps) => { return ( <div data-keyMatch={matchId} onClick={handleChoice} className="p-4 bg-white rounded shadow" > <p>{word[0]}</p> </div> ); }; export default MatchingCards;
3. 卡组初始化的异步问题
handleMatchingGameClick中调用doubleTheDeck后立即执行shuffle(doubledDeck),但doubledDeck更新是异步的,此时传入的仍是旧数组。需用useEffect监听doubledDeck变化来执行洗牌:
useEffect(() => { if (doubledDeck.length > 0) { shuffle(doubledDeck); } }, [doubledDeck]); const handleMatchingGameClick = () => { doubleTheDeck(cardsForMatchingGame); setMatchingGameActive(prev => !prev); }; // 渲染时直接生成卡组,无需存入state // 替换return中的卡组渲染部分: {matchingGameActive ? shuffledDeck.map(card => ( <MatchingCards key={card.matchId + card.word[0]} matchId={card.matchId} word={card.word} handleChoice={handleChoice} /> )) : cards}
内容的提问来源于stack exchange,提问作者Boon
相关产品推荐
相关产品推荐

