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

React开发DnD 5e角色表:种族属性加成无法重置问题求助

解决方案:修复DnD 5e角色表种族属性加成重置问题

问题根源

你当前的实现直接修改了状态中的属性值,导致基础属性被种族加成“污染”——切换种族时无法回退到用户最初选择的基础值,重复选择同一种族还会持续累加加成。核心问题是没有分离「用户选择的基础属性」和「种族加成」。

核心修复思路

  1. 拆分状态:分别存储用户选择的基础属性和选中的种族,不直接修改基础属性值
  2. 动态计算最终属性:每次渲染时,基于基础属性+当前种族的加成计算出最终显示值
  3. 正确更新状态:使用React的setState更新状态,避免直接修改state对象

完整代码修改示例

1. 重构状态定义

import { useState } from 'react';

// 定义状态接口(TypeScript可选,但推荐)
interface CharacterState {
  baseStats: number[]; // 用户选择的基础属性值(对应力量、敏捷、体质、智力、感知、魅力)
  selectedSpecies: string; // 当前选中的种族
}

// 初始化状态:假设standardArray对应6个属性,初始值可根据需求调整
const initialState: CharacterState = {
  baseStats: [10, 10, 10, 10, 10, 10],
  selectedSpecies: ""
};

const CharacterSheet = () => {
  const [state, setState] = useState<CharacterState>(initialState);

2. 修改属性选择的处理函数

// 更新基础属性,不直接叠加加成
const handleChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
  const statIndex = parseInt(e.target.name.replace("playerStat", ""));
  const newValue = parseInt(e.target.value);
  
  setState(prev => ({
    ...prev,
    baseStats: prev.baseStats.map((stat, idx) => 
      idx === statIndex ? newValue : stat
    )
  }));
};

3. 修改种族选择的处理函数

// 仅保存选中的种族,不直接修改属性
const handleSpeciesChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
  setState(prev => ({
    ...prev,
    selectedSpecies: e.target.value
  }));
};

4. 编写种族加成计算函数

// 根据当前种族计算属性加成
const calculateSpeciesBonuses = (): number[] => {
  const bonuses = new Array(6).fill(0); // 默认所有属性加0

  switch(state.selectedSpecies) {
    case "Orc":
      bonuses[0] = 1; // 力量(第1个属性)+1
      break;
    case "Elf":
      bonuses[3] = 1; // 智力(第4个属性)+1
      break;
    case "Human":
      bonuses.fill(1); // 人类所有属性+1(可根据DnD规则调整)
      break;
    default:
      break;
  }

  return bonuses;
};

// 计算最终属性值:基础值 + 种族加成
const getFinalStats = () => {
  const bonuses = calculateSpeciesBonuses();
  return state.baseStats.map((base, idx) => base + bonuses[idx]);
};

5. 渲染更新后的组件

// 属性赋值组件渲染
return (
  <div>
    {standardArray.map((stat, index) => {
      const finalStat = getFinalStats()[index];
      return (
        <div key={index}>
          <Text marginLeft={5}>
            {stat.name[index]}: {finalStat} {/* 显示最终属性值 */}
          </Text>
          <Select
            placeholder={stat.name[index]}
            width="90%"
            marginLeft={3}
            marginBottom={3}
            onChange={handleChange}
            value={state.baseStats[index].toString()} {/* 绑定基础属性值 */}
            name={"playerStat" + index}
          >
            {stat.value.map((value, idx) => (
              <option key={idx} value={value}>
                {value}
              </option>
            ))}
          </Select>
        </div>
      );
    })}

    {/* 种族选择组件 */}
    <Select
      placeholder="Choose a Species"
      color="White"
      marginLeft={3}
      marginRight={3}
      width="90%"
      onChange={handleSpeciesChange}
      value={state.selectedSpecies}
      name="playerSpecies"
    >
      <option value="Orc">Orc</option>
      <option value="Elf">Elf</option>
      <option value="Human">Human</option>
    </Select>
  </div>
);
};

export default CharacterSheet;

关键改进点

  • 彻底分离了基础属性和加成,切换种族时会自动重新计算最终值,不会保留旧加成
  • 使用React的状态更新规范,避免直接修改state对象导致的状态不一致问题
  • 加成逻辑集中在calculateSpeciesBonuses函数中,后续新增种族只需扩展switch分支即可,维护性更强

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 00:27:06