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

React文本游戏可变变量问题求助:状态仅初始更新一次

解决React版《Dragon Repeller》游戏状态更新异常问题

问题核心

你遇到的问题根源有三个:

  • 将按钮函数存入React状态时,函数会形成闭包捕获初始状态值,后续状态更新后,旧函数仍引用旧状态,导致逻辑判断和更新出错
  • update函数中访问按钮文本的语法错误(location['buttonText'[0]]应为location['button text'][0])
  • 状态结构冗余(用对象包裹单个值,增加不必要的层级复杂度)

修复方案

1. 简化状态结构

把嵌套对象状态改为直接存储基础值,减少层级,让状态操作更直观:

const [health, setHealth] = useState(100);
const [gold, setGold] = useState(50);
const [text, setText] = useState('Welcome to Dragon Repeller. You must defeat the dragon that is preventing people from leaving the town. You are in the town square. Where do you want to go? Use the buttons above.');
// 新增当前位置索引状态,替代单独存储按钮文本和函数
const [currentLocationIndex, setCurrentLocationIndex] = useState(0);

2. 移除buttonFunction状态

不再将函数存入状态,直接通过当前位置索引获取对应函数,彻底避免闭包捕获旧状态的问题。

3. 重构update函数逻辑

改为更新当前位置索引,所有按钮文本和逻辑都基于当前位置动态获取:

function update(locationIndex) {
  setCurrentLocationIndex(locationIndex);
  setText(locations[locationIndex].text);
}

4. 动态渲染按钮

在JSX中直接根据currentLocationIndex获取按钮文本并绑定点击事件,无需额外状态存储:

<button 
  id="button1" 
  className='gButton' 
  onClick={() => locations[currentLocationIndex]['button functions'][0]()}
>
  {locations[currentLocationIndex]['button text'][0]}
</button>

修正后的完整代码

import { useState } from 'react';

export default function DragonRepeller() {
  const [health, setHealth] = useState(100);
  const [gold, setGold] = useState(50);
  const [text, setText] = useState('Welcome to Dragon Repeller. You must defeat the dragon that is preventing people from leaving the town. You are in the town square. Where do you want to go? Use the buttons above.');
  const [currentLocationIndex, setCurrentLocationIndex] = useState(0);

  const locations = [
    {
      name: "town square",
      "button text": ["Go to store", "Go to cave", "Fight dragon"],
      "button functions": [goStore, goCave, fightDragon],
      text: "You are in the town square. You see a sign that says \"Store\"."
    },
    {
      name: "store",
      "button text": ["Buy 10 health (10 gold)", "Buy weapon (30 gold)", "Go to town square"],
      "button functions": [buyHealth, buyWeapon, goTown],
      text: "You enter the store."
    },
    {
      name: "cave",
      "button text": ["Fight slime", "Fight fanged beast", "Go to town square"],
      "button functions": [fightSlime, fightBeast, goTown],
      text: "You enter the cave. You see some monsters."
    }
    // 可补充其他位置数据
  ];

  function update(locationIndex) {
    setCurrentLocationIndex(locationIndex);
    setText(locations[locationIndex].text);
  }

  function goTown() {
    update(0);
  };

  function goStore() {
    update(1);
  };

  function goCave() {
    update(2);
  };

  function buyHealth() {
    if (gold >= 10) {
      setGold(prev => prev - 10);
      setHealth(prev => prev + 10);
    } else {
      setText('You do not have enough gold to buy health');
    }
  }

  function buyWeapon() {
    if (gold >= 30) {
      setGold(prev => prev - 30);
      setText('You bought a new weapon!');
    } else {
      setText('You do not have enough gold to buy a weapon');
    }
  }

  function fightSlime() {
    setText('You fought a slime and won! You gained 10 gold.');
    setGold(prev => prev + 10);
  }

  function fightBeast() {
    setText('You fought a fanged beast and survived! You gained 20 gold.');
    setGold(prev => prev + 20);
    setHealth(prev => prev - 15);
  }

  function fightDragon() {
    setText('You fought the dragon and...');
    // 补充战斗龙的逻辑
  }

  const currentLocation = locations[currentLocationIndex];

  return (
    <div id="game">
      <div id='stats'>
        <span className='stat'>Health: <strong><span id='healthText'>{health}</span></strong></span>
        <span className='stat'>Gold: <strong><span id='goldText'>{gold}</span></strong></span>
      </div>
      <div id="controls">
        <button 
          id="button1" 
          className='gButton' 
          onClick={() => currentLocation['button functions'][0]()}
        >
          {currentLocation['button text'][0]}
        </button>
        <button 
          id="button2" 
          className='gButton' 
          onClick={() => currentLocation['button functions'][1]()}
        >
          {currentLocation['button text'][1]}
        </button>
        <button 
          id="button3" 
          className='gButton' 
          onClick={() => currentLocation['button functions'][2]()}
        >
          {currentLocation['button text'][2]}
        </button>
      </div>
      <div id='text'>
        {text}
      </div>
    </div>
  );
}

关键说明

  • 用currentLocationIndex状态跟踪当前位置,所有按钮文本和逻辑都基于这个索引动态获取,彻底避免闭包捕获旧状态的问题
  • 简化状态结构后,状态更新和读取更直观,减少出错概率
  • 移除了冗余的buttonText和buttonFunction状态,让组件逻辑更清晰

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 04:11:14