You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Bingo游戏点击样式切换与重置功能异常求助

Bingo游戏重置时单元格高亮无法清除的解决方案

问题根源

  1. Cell组件的matched状态仅在组件初始化时读取reset props,后续reset变化不会触发matched更新——useState的初始值只执行一次。
  2. pickRandomWords中setReset(true)后未将reset重置为false,导致后续点击"New Game"时reset状态无变化,无法触发Cell的状态更新。
  3. 额外问题: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 21:15:34