这最初是一个来自免费代码阵营的JS项目,但为了把它放到我的投资组合网站上,我想让它具有互动性.

我try 将变量设置为STATE并通过props 向下传递,但变量最初只会变异一次,并且显示不会更新更多.以下是一些代码,应该可以让您对整个项目有一个了解.

按钮函数、按钮文本和文本的状态都将正确更新和显示,但按钮函数只设置一次状态并继续调用原始状态.

//JSX file
export default function DragonRepeller() {
const [health, setHealth] = useState({ health: 100 });
const [gold, setGold] = useState({ gold: 50 });
const [text, setText] = useState({ text: '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 [buttonText, setButtonText] = useState({ button1: "Go To Store", button2: 'Go to Cave', button3: 'Fight Dragon'});
const button1Text = buttonText.button1
const button2Text = buttonText.button2
const button3Text = buttonText.button3
const [buttonFunction, setButtonFunction] = useState({button1: goStore, button2: goCave, button3: fightDragon});
const button1Function = buttonFunction.button1
const button2Function = buttonFunction.button2
const button3Function = buttonFunction.button3
// various other initializers and some objects 
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."
        },
        {/*location[2] commented out for space*/},
        {/*location[3]*/},
        {/*location[4]*/},
        {/*location[5]*/},
        {/*location[6]*/},
        {/*location[7]*/}
    ];
//location functions
    function update(location) {
        setButtonText(() => {
            return {
                button1: location['buttonText'[0]],
                button2: location['buttonText'[1]],
                button3: location['buttonText'[2]]
            }
        });
        setButtonFunction(() => {
            return {
                button1: location['button functions'][0],
                button2: location['button functions'][1],
                button3: location['button functions'][2]
            }
        });
        setText(() => {
            return { text: location.text}
        });
        };
//button functions that use the update(location) function
function goTown() { // starting location
        update(locations[0]);
    };
    function goStore() { // this is the location with the function in question
        update(locations[1]);
    };
    function goCave() {
        update(locations[2]);
    };
//buy health button function, buy weapon works the same 
function buyHealth() {
    if (gold.gold >= 10) {
       setGold((prevGold) => { return { gold: prevGold.gold - 10 }});
       setHealth((prevHealth) => { return { health: prevHealth.health + 10 }});
  } else {
       setText(() => { return { text: 'You do not have enough gold to buy health' }});
  }
 }
//the rest of the code
}
return (
<div id=game>
   <div id='stats'>
      <span className='stat'>Health: <strong><span id='healthText'>{health.health}</span></strong></span>
      <span className='stat'>Gold: <strong><span id='goldText'>{gold.gold}</span></strong></span>
   </div>
   <div id="controls">
       <button id="button1" className='gButton' onClick={button1Function}>{button1Text}</button>
       <button id="button2" className='gButton' onClick={button2Function}>{button2Text}]</button>
       <button id="button3" className='gButton' onClick={button3Function}>{button3Text}</button>
   </div>
   <div id='text'>
      {text.text}
   </div>
</div>
)

我觉得我走错了路,需要一些帮助.

我已经多次try 用不同的方式设置状态来重写代码.每次我运行代码时,文本都会随着我设置的更改内容而不断更新,但其他变量只会变异一次,然后它们要么恢复到初始状态,要么恢复到它改变的第一种方式.

我try 了普通的JS而不是JSX,但遇到了更多函数无法执行的问题.

我也一直在搜索堆栈溢出,以寻找可能与此相关的任何东西,但我没有找到任何有效的解决方案,这让我觉得我遗漏了这里的一个关键点.

推荐答案

Issue

您已经在buyHealth回调函数中关闭了gold状态,该函数在locations对象中关闭,根据您在游戏中的行进位置,locations对象在buttonFunction状态下关闭.

换句话说,它是一个陈旧的Java脚本Closure,当状态实际更改时,gold.gold的值不会更新为外部作用域的值,直到您将buttonFunction更新为不同的状态,然后返回以将当前的gold状态值重新包含在回调堆栈中.

Solution

我在这里建议的解决方案是创建要分配给UI按钮1、2和3的回调的查找映射,并在运行时使用Function组件闭包的当前值调用这些回调.查找应按状态中存储的位置进行,而不是按状态中存储的回调进行.

示例:

const LOCATION = {
  CAVE: "CAVE",
  STORE: "STORE",
  TOWN: "TOWN",
};

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 [location, setLocation] = useState("town");

  function goTown() {
    setLocation(LOCATION.TOWN);
    setText(locations[LOCATION.TOWN].text);
  };

  function goStore() {
    setLocation(LOCATION.STORE);
    setText(locations[LOCATION.STORE].text);
  };

  function goCave() {
    setLocation(LOCATION.CAVE);
    setText(locations[LOCATION.CVE].text);
  };

  // buy health button function, buy weapon works the same 
  function buyHealth() {
    if (gold >= 10) {
      setGold(gold => gold - 10);
      setHealth(health => health + 10);
    } else {
      setText('You do not have enough gold to buy health');
    }
  }

  const locations = {
    [LOCATION.CAVE]: {
      ....
    },
    [LOCATION.TOWN]: {
      name: "town square",
      buttons: [
        { text: "Go to store", handler: goStore },
        { text: "Go to cave", handler: goCave },
        { text: "Fight dragon", handler: fightDragon }
      ],
      text: 'You are in the town square. You see a sign that says "Store".'
    },
    [LOCATION.STORE]: {
      name: "store",
      buttons: [
        { text: "Buy 10 health (10 gold)", handler: buyHealth },
        { text: "Buy weapon (30 gold)", handler: buyWeapon },
        { text: "Go to town square", handler: goTown }
      ],
      text: "You enter the store."
    },
  };

  ...

  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">
        {locations[location].buttons.map((button, i) => (
          <button
            key={button.text}
            id={`button${i + 1}`}
            className='gButton'
            onClick={button.handler}
          >
            {button.text}
          </button>
        ))}
      </div>
      <div id='text'>
        {text}
      </div>
    </div>
  );
}

Javascript相关问答推荐

禁用从vue.js 2中的循环创建的表的最后td的按钮

如何解决这个未能在响应上执行json:body stream已读问题?

如何避免移动设备中出现虚假调整大小事件?

Phaser框架-将子对象附加到Actor

在React中获取数据后,如何避免不必要的组件闪现1秒?

Cookie中未保存会话数据

类型自定义lazy Promise. all

处理时间和字符串时MySQL表中显示的日期无效

还原器未正确更新状态

变量的值在Reaction组件中的Try-Catch语句之外丢失

WhatsApp Cloud API上载问题:由于MIME类型不正确而导致接收&Quot;INVALID_REQUEST";错误

查询参数中的JAVASCRIPT/REACT中的括号

触发异步函数后不能显示数据

为什么当我更新数据库时,我的所有组件都重新呈现?

是否可以将异步调用与useState(UnctionName)一起使用

AG-GRIDreact 显示布尔值而不是复选框

有没有办法在R中创建一张具有多个色标的热图?

在对象的嵌套数组中添加两个属性

如何从Reaction-Redux中来自API调用的数据中筛选值

从客户端更新MongoDB数据库