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

React开发2048游戏:点击按钮连续两次更新state仅单次生效

问题根源

连续调用两次generate()只生成一个2的本质原因是React的状态更新是异步批处理的:同一事件回调中执行两次generate()时,闭包内捕获到的Board始终是事件执行前的初始空棋盘,两次生成操作都基于同一份旧状态计算,最终后一次setBoard会覆盖前一次的更新结果。同时原generate()中随机到非空位置就递归调用自身的逻辑,在状态未同步更新的场景下还可能触发无限递归。

修复方案

核心修改点是使用React的函数式状态更新,确保每次修改棋盘时都能拿到上一次更新完成的最新状态,同时优化随机生成逻辑,先筛选所有空位再随机选择,避免不必要的递归:

import { useState, useEffect } from 'react';

const width = 4;

const Game = () => {
  const [Board, setBoard] = useState([]);

  const createBoard = () => {
    let initialBoard = [];
    for (let i = 0; i < width * width; i++) {
      initialBoard.push("");
    }
    return initialBoard;
  };

  // 基于传入的最新棋盘生成一个新块,返回更新后的棋盘
  const addRandomTile = (currentBoard) => {
    // 先找出所有空位置
    const emptyPositions = [];
    currentBoard.forEach((val, idx) => {
      if (val === "") emptyPositions.push(idx);
    });
    // 没有空位直接返回原棋盘
    if (emptyPositions.length === 0) return currentBoard;
    // 从空位置里随机选一个填2
    const randomIdx = Math.floor(Math.random() * emptyPositions.length);
    const targetPos = emptyPositions[randomIdx];
    const newBoard = [...currentBoard];
    newBoard[targetPos] = 2;
    return newBoard;
  };

  const handleNewGame = () => {
    // 先初始化空棋盘,再连续加两个2,全程用函数式更新拿到最新状态
    setBoard(createBoard());
    setBoard(prevBoard => addRandomTile(prevBoard));
    setBoard(prevBoard => addRandomTile(prevBoard));
  }

  useEffect(() => {
    handleNewGame();
    console.log(`Board Created!`);
  }, []);

  return (
    <div className="game-container">
      <button onClick={handleNewGame}>NewGame</button>
      <div className="game">
        {Board.map((value, index) => (
          <div className="tile" key={index}>
            {value}
          </div>
        ))}
      </div>
    </div>
  );
};

export default Game;
关键改动说明
  • 把生成方块的逻辑抽成纯函数addRandomTile,接收当前最新棋盘作为参数,不依赖组件闭包内的旧状态
  • 所有状态更新都使用setBoard(prev => 新值)的函数式写法,保证链式调用时每一步都能拿到上一步更新完成的最新状态
  • 替换原有的随机+递归判断逻辑,先收集所有空位再随机选择,从根源上避免随机到非空位置的无效计算和递归风险
  • 初始化和新游戏逻辑统一收敛到handleNewGame,首次加载和点击按钮复用同一套逻辑,保证初始棋盘一定生成2个随机2块

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 20:06:26