skip to Main Content

I’m trying to build a react app that exports a DnD 5e character sheet. There are different bonuses based on your selected race/species. I have a dropdown menu to select your race and I want to apply the bonus to the appropriate stat. The problem is that if I then select a different option it doesn’t revert the stats. So if I click "Orc" I get a +1 to strength, but if I change it to "Elf", I get a +1 to intelligence but the +1 to strength sticks around and going back to "Orc" adds another +1 to strength. Any advice on setting these conditional bonuses?

Here is the function that assigns the stat values

    <div>
          {standardArray.map((stat, index) => {
            return (
              <div key={index}>
                <Text marginLeft={5}> {stat.name[index]}</Text>
                <Select
                  placeholder={stat.name[index]}
                  width="90%"
                  marginLeft={3}
                  marginBottom={3}
                  onChange={handleChange}
                  name={"playerStat" + [index]}
                >
                  Name: {stat.name}
                  {stat.value.map((value, index) => {
                    return (
                      <option key={index} value={value}>
                        {value}
                      </option>
                    );
                  })}
                </Select>
              </div>
            );
          })}
        </div>

This is the dropdown menu that calls the bonus function

    <Select
          placeholder="Choose a Species"
          color={"White"}
          marginLeft={3}
          marginRight={3}
          width="90%"
          onChange={handleSpeciesChange}
          value={state.playerSpecies}
          name="playerSpecies"
        >
          <option value="Orc">Orc</option>
          <option value="Elf">Elf</option>
          <option value="Human">Human</option>
        </Select>

This is the function that applies the bonus

  const speciesBonus = (value: string) => {
    if (value === "Orc") {
      const speciesBonus = 1;
      state.playerStat0 = parseInt(state.playerStat0) + speciesBonus;
    }
    if (value === "Elf") {
      const speciesBonus = 1;
      state.playerStat3 = parseInt(state.playerStat3) + speciesBonus;
    } else {
      state.playerStat0 = parseInt(state.playerStat0);
    }
  };


  [1]: https://i.sstatic.net/Ia3mceWk.png
  [2]: https://i.sstatic.net/Yjdc48hx.png
  [3]: https://i.sstatic.net/ICMR3tWk.png

2

Answers


  1. I’m going to answer from a RPG perspective, as much as from a tech perspective.

    Species selection impacts more than just base stats. You’re going to want a record of which specie the character belongs to long-term, for things like racial abilities, or for some wild situations like Reincarnate.

    Instead of directly updating the character’s stats, add the selected specie as a data field that you store itself. Then use something similar your speciesBonus to determine the correct value to display for each stat, without actually updating it on the state.

    As a side effect, doing this will solve your tech issue.

    For completeness, though, your issue stems from the fact that your speciesBonus function only applies the new species bonus. If you wanted to update it with this same structure, you would need to change speciesBonus signature to accept both a current and previous species, so you could "undo" the previous selection’s benefits.

    Login or Signup to reply.
  2. You could try to store the species bonuses in an object with key: speciesName, value: bonusesArray

    const bonuses = {
      Orc: [1,0,0,0,0,-2],
      Elf: [0,1,0,0,0,0],
      // etc
    };
    

    Each time the user selects a species, you are going to:

    • check if a species was previously assigned. If so, remove the bonus for the old species
    • get the new species, and apply the bonus

    For this you will need a state variable like "currentSelectedSpecies" to store the currently selected species.

    I modified handleSpeciesChange to do that. I tried to only call setState once, so I got rid of the separate function.

    Warning. I’ve not used setState before and none of this code is tested.

    const handleSpeciesChange = (e) => {
      const {value} = e.target;
      const lastValue = state.currentSelectedSpecies;
    
      if (lastValue === value) return;
    
      // get current playerAttributes from state
      const attrs = ["0","1","2","3","4","5"].map(v => state[`playerAttribute${v}`]);
    
      // only remove the last species bonuses if one was picked
      if (lastValue) {
        lastBonuses = bonuses[lastValue];
        lastBonuses.forEach((b, i) => attrs[i] -= b);
      }
      
      newBonuses = bonuses[value];
      newBonuses.forEach((b, i) => attrs[i] += b);
    
      setState(prevState => ({
        ...prevState,
        playerAttribute0: attrs[0],
        playerAttribute1: attrs[1],
        playerAttribute2: attrs[2],
        playerAttribute3: attrs[3],
        playerAttribute4: attrs[4],
        playerAttribute5: attrs[5],
        currentSelectedSpecies: value
      }));
    };
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search