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

React开发扫雷游戏遇变量重复声明致无限循环,如何声明不可变变量?

问题分析与解决方案

核心问题

  1. 全局变量失效:外部声明的let nrbomb = 40,组件每次重渲染时,虽然变量本身不会被重新声明,但组件内inc == 1 && rendergame == 0分支会重复执行,加上循环中直接修改全局变量,会导致状态与变量值不同步,且全局变量不被React追踪,无法触发正确渲染。
  2. 渲染阶段更新状态导致无限循环:若用useState存储nrbomb,在渲染逻辑(while循环)里调用setState,每次状态更新都会触发组件重渲染,进而再次进入循环,形成无限循环。
  3. 对象引用共享问题:你创建的mine_grid中,所有格子都引用同一个square对象,修改任意一个格子的bomb或viz属性,会导致所有格子属性同时变化,属于严重逻辑错误。

解决步骤

1. 修复格子对象引用问题

创建网格时,每个格子都要生成新对象,避免复用同一个引用:

// 初始化网格,每个格子都是独立对象
const initialGrid = Array(n).fill().map(() => 
  Array(n).fill().map(() => ({ bomb: 0, viz: 0 }))
)

2. 用useEffect处理炸弹生成逻辑

不要在渲染阶段直接更新状态,改用useEffect监听inc变化,一次性完成炸弹生成并更新状态:

import { useState, useEffect } from 'react'
import './App.css'

function App() {
  const n = 12
  const totalBombs = 40 // 炸弹数量作为常量,无需全局/state存储

  const initialGrid = Array(n).fill().map(() => 
    Array(n).fill().map(() => ({ bomb: 0, viz: 0 }))
  )

  const [inc, change_inc] = useState(0)
  const [mine_grid, change_mine_grid] = useState(initialGrid)
  const [cx, change_cx] = useState(0)
  const [cy, change_cy] = useState(0)
  const [rendergame, change_render_game] = useState(0)

  // 监听inc变化,触发炸弹生成
  useEffect(() => {
    if (inc === 1 && rendergame === 0) {
      // 深拷贝网格,避免直接修改原状态
      const newGrid = JSON.parse(JSON.stringify(mine_grid))
      let remainingBombs = totalBombs

      while (remainingBombs > 0) {
        const x = Math.floor(Math.random() * n)
        const y = Math.floor(Math.random() * n)
        // 跳过已点击格子和已有炸弹的格子
        if (newGrid[x][y].viz === 0 && newGrid[x][y].bomb === 0) {
          newGrid[x][y].bomb = 1
          remainingBombs--
        }
      }

      // 一次性更新网格和状态,避免多次重渲染
      change_mine_grid(newGrid)
      change_render_game(1)
    }
  }, [inc, rendergame, mine_grid, n, totalBombs])

  if (inc === 0) {
    return (
      <div className="all">
        <div className="grid_container">
          {mine_grid.map((arr, i) => {
            return arr.map((e, j) => {
              return (
                <div
                  key={`${i}-${j}`} // 添加唯一key,避免React渲染错误
                  style={{
                    background: 'green',
                    width: '50px',
                    height: '50px',
                    margin: '5px',
                  }}
                ></div>
              )
            })
          })}
        </div>
        <h6>for x:</h6>
        <input
          type="number"
          value={cx}
          onChange={(e) => change_cx(Number(e.target.value))}
        ></input>
        <h6>for y:</h6>
        <input
          type="number"
          value={cy}
          onChange={(e) => change_cy(Number(e.target.value))}
        ></input>
        <button
          type="button"
          onClick={() => {
            if (cx >=0 && cx < n && cy >=0 && cy < n) {
              const newGrid = JSON.parse(JSON.stringify(mine_grid))
              newGrid[cx][cy].viz = 1
              change_mine_grid(newGrid)
              change_inc(1)
            }
          }}
        >
          Submit move
        </button>
      </div>
    )
  }

  // 生成炸弹后的游戏界面
  return (
    <div className="grid_container">
      {mine_grid.map((arr, i) => (
        arr.map((e, j) => (
          <div
            key={`${i}-${j}`}
            style={{
              background: e.viz ? (e.bomb ? 'red' : 'gray') : 'green',
              width: '50px',
              height: '50px',
              margin: '5px',
              display: 'flex',
              alignItems: 'center',
              justifyContent: 'center',
              fontSize: '24px'
            }}
          >
            {e.viz && e.bomb ? '💣' : ''}
          </div>
        ))
      ))}
    </div>
  )
}

export default App

3. 关键说明

  • 避免渲染阶段更新状态:useEffect是React处理副作用的正确方式,仅在依赖项变化时执行,不会重复触发循环。
  • 临时变量替代全局/state变量:炸弹剩余数量remainingBombs是生成逻辑内的临时变量,生成完成后无需留存,不需要存入state或全局变量。
  • 状态不可变性:修改网格时必须创建新的数组/对象(如深拷贝),不能直接修改原状态对象,否则React无法检测状态变化,不会触发重渲染。
  • 添加唯一key:列表渲染时必须给每个元素加唯一key,避免React渲染错误和性能问题。

内容的提问来源于stack exchange,提问作者No0bYebY

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 10:32:23