React Bingo游戏点击样式切换与重置功能异常求助
Bingo游戏重置时单元格高亮无法清除的解决方案
问题根源
Cell组件的matched状态仅在组件初始化时读取resetprops,后续reset变化不会触发matched更新——useState的初始值只执行一次。pickRandomWords中setReset(true)后未将reset重置为false,导致后续点击"New Game"时reset状态无变化,无法触发Cell的状态更新。- 额外问题:
groupOfWords.sort()会直接修改原数组,属于不良实践,应先浅拷贝数组再排序。
方案一:监听reset props重置Cell状态
修改App.js
调整pickRandomWords逻辑,确保每次点击都能触发reset状态的完整变化流程:
import { useState, useEffect } from 'react' import './App.css'; import Cell from './components/Cell'; function App() { const [words, setWords] = useState([]) const [reset, setReset] = useState(false) const groupOfWords = [ { "word": "hello", id: 1}, { "word": "react", id: 2}, { "word": "gaming", id: 3}, { "word": "university", id: 4}, { "word": "yoooo", id: 5}, { "word": "hockey", id: 6}, { "word": "programming", id: 7}, { "word": "xbox", id: 8}, { "word": "digging", id: 9}, { "word": "car", id: 10} ] const pickRandomWords = () => { setReset(true) // 浅拷贝原数组再打乱,避免修改原数据 const shuffled = [...groupOfWords].sort(() => 0.5 - Math.random()) setWords(shuffled.slice(0, 8)) } // 单词更新后重置reset状态,确保下次点击能触发新的变化 useEffect(() => { if (words.length > 0) { setReset(false) } }, [words]) return ( <div className="App"> <h1>Bingo</h1> <button onClick={pickRandomWords}>New Game</button> <div className='grid'> {words.map(w => ( <Cell key={w.id} word={w.word} reset={reset}/> ))} </div> </div> ); } export default App;
修改Cell.js
添加useEffect监听reset props,触发状态重置:
import './Cell.css' import { useState, useEffect } from 'react' export default function Cell({ word, reset }) { const [matched, setMatched] = useState(false) // 监听reset变化,重置高亮状态 useEffect(() => { if (reset) { setMatched(false) } }, [reset]) const highlightCell = () => { setMatched(true) } // 修正className逻辑:matched为true时应用高亮样式 return ( <div className={matched ? 'cellMatched' : 'cell'} onClick={highlightCell}> <p>{word}</p> </div> ) }
方案二:修改key强制Cell重新挂载
这种方式更简洁,不需要维护reset状态,通过修改组件key让Cell每次新游戏时重新初始化:
修改App.js
新增gameRound状态,每次点击"New Game"时递增,用来拼接Cell的key:
import { useState } from 'react' import './App.css'; import Cell from './components/Cell'; function App() { const [words, setWords] = useState([]) const [gameRound, setGameRound] = useState(0) // 新增游戏轮次状态 const groupOfWords = [ { "word": "hello", id: 1}, { "word": "react", id: 2}, { "word": "gaming", id: 3}, { "word": "university", id: 4}, { "word": "yoooo", id: 5}, { "word": "hockey", id: 6}, { "word": "programming", id: 7}, { "word": "xbox", id: 8}, { "word": "digging", id: 9}, { "word": "car", id: 10} ] const pickRandomWords = () => { const shuffled = [...groupOfWords].sort(() => 0.5 - Math.random()) setWords(shuffled.slice(0, 8)) setGameRound(prev => prev + 1) // 递增轮次,强制Cell重新挂载 } return ( <div className="App"> <h1>Bingo</h1> <button onClick={pickRandomWords}>New Game</button> <div className='grid'> {words.map(w => ( <Cell key={`${w.id}-${gameRound}`} // 用轮次拼接key word={w.word}/> ))} </div> </div> ); } export default App;
修改Cell.js
去掉reset相关逻辑,恢复基础状态即可:
import './Cell.css' import { useState } from 'react' export default function Cell({ word }) { const [matched, setMatched] = useState(false) const highlightCell = () => { setMatched(true) } return ( <div className={matched ? 'cellMatched' : 'cell'} onClick={highlightCell}> <p>{word}</p> </div> ) }
内容的提问来源于stack exchange,提问作者dynamo
相关产品推荐
相关产品推荐

