React开发DnD 5e角色表:种族属性加成无法重置问题求助
解决方案:修复DnD 5e角色表种族属性加成重置问题
问题根源
你当前的实现直接修改了状态中的属性值,导致基础属性被种族加成“污染”——切换种族时无法回退到用户最初选择的基础值,重复选择同一种族还会持续累加加成。核心问题是没有分离「用户选择的基础属性」和「种族加成」。
核心修复思路
- 拆分状态:分别存储用户选择的
基础属性和选中的种族,不直接修改基础属性值 - 动态计算最终属性:每次渲染时,基于基础属性+当前种族的加成计算出最终显示值
- 正确更新状态:使用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
相关产品推荐
相关产品推荐

