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

React开发Blackjack游戏:while循环中useState引发无限循环

问题原因分析
  1. React State异步更新导致循环条件失效:setDealerCards是异步操作,在while循环中调用时,dealerCards的状态不会立即更新,循环条件getHandValue(dealerCards) < 17始终基于初始值判断,永远为真,触发无限循环。
  2. 牌堆每次渲染重复洗牌:shuffledDeck直接在组件顶层定义,组件每次重新渲染都会执行shuffleDeck(deck),导致牌堆被反复打乱,取牌逻辑完全混乱。
  3. 取牌索引逻辑错误:循环中取牌依赖dealerCards.length,但由于state未更新,每次取的都是同一个位置的牌,即使state能更新,也会重复取同一张牌。
解决方案

1. 修复牌堆洗牌逻辑,避免重复打乱

使用useMemo缓存洗牌后的牌堆,确保仅在组件初始化时洗牌一次:

import { useMemo, useState } from 'react';

// ...其他代码

const shuffledDeck = useMemo(() => shuffleDeck([...deck]), []);

同时修改shuffleDeck为纯函数,避免修改原数组:

const shuffleDeck = (deck: Card[]): Card[] => {
  const newDeck = [...deck]; // 复制原数组,避免污染输入
  for (let i = newDeck.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [newDeck[i], newDeck[j]] = [newDeck[j], newDeck[i]];
  }
  return newDeck;
};

2. 重构庄家抽牌逻辑,避免异步State循环

用临时变量同步计算庄家最终手牌,一次性更新State,彻底解决循环问题:

const handleStand = () => {
  if (gameState !== 'playing') return;

  // 用临时变量跟踪庄家手牌,同步更新,不依赖异步State
  let currentDealerCards = [...dealerCards];
  // 计算当前已用牌的数量,确定下一张牌的索引
  let nextCardIndex = playerCards.length + currentDealerCards.length;

  // 循环抽牌直到手牌值≥17,同时避免牌堆耗尽
  while (getHandValue(currentDealerCards) < 17 && nextCardIndex < shuffledDeck.length) {
    currentDealerCards.push(shuffledDeck[nextCardIndex]);
    nextCardIndex++;
  }

  // 一次性更新庄家手牌State
  setDealerCards(currentDealerCards);

  // 计算胜负结果
  const dealerHandValue = getHandValue(currentDealerCards);
  const playerHandValue = getHandValue(playerCards);

  if (dealerHandValue > 21 || dealerHandValue < playerHandValue) {
    setGameState('won');
    setPlayerBalance(prev => prev + currentBet); // 用函数式更新确保取到最新余额
  } else if (dealerHandValue > playerHandValue) {
    setGameState('lost');
    setPlayerBalance(prev => prev - currentBet);
  } else {
    setGameState('tied');
  }
};

补充说明

  • 使用函数式更新setPlayerBalance(prev => ...)是为了确保基于最新的余额状态计算,避免因State异步更新导致的计算错误。
  • 增加nextCardIndex < shuffledDeck.length的判断,防止牌堆耗尽时继续取牌导致报错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 06:50:52