Tye
Tye

Reputation: 1

What is the best method to change React State based off of State?

I am in the process of building a React app and I want to be able to set the state of upperScoreBonus as soon as all of the other scores are not undefined. If the total of the all the scores are greater than 63, then add the bonus, otherwise only score 0.

Where I'm stuck is the applyUpperScoreBonus function is delayed until the next time that the roll function is called. I'm at a loss on where I should make this call to applyUpperScoreBonus.

I know I'm missing something.

class Game extends Component {
  constructor(props) {
    super(props);
    this.state = {
      dice: Array.from({ length: NUM_DICE }),
      locked: Array(NUM_DICE).fill(false),
      rollsLeft: NUM_ROLLS,
      isRolling: false,
      scores: {
        ones: undefined,
        twos: undefined,
        threes: undefined,
        fours: undefined,
        fives: undefined,
        sixes: undefined,
        upperBonusScore: undefined
      }
    };
    this.roll = this.roll.bind(this);
    this.doScore = this.doScore.bind(this);
    this.applyUpperScoreBonus = this.applyUpperScoreBonus.bind(this);
  }

    doScore(rulename, ruleFn) {
    // evaluate this ruleFn with the dice and score this rulename
    // only allows an update to the score card if the vaule has not yet been set. 

    if (this.state.scores[rulename] === undefined) {
      this.setState(st => ({
        scores: { ...st.scores, [rulename]: ruleFn(this.state.dice)},
        rollsLeft: NUM_ROLLS,
        locked: Array(NUM_DICE).fill(false)
      }));

      this.applyUpperScoreBonus();
      this.roll();

    }
  }

  applyUpperScoreBonus() {

    const st = this.state.scores;
    const upperArrayScores = [st.ones, st.twos, st.threes, st.fours, st.fives, st.sixes];
    let totalUpperScore = 0; 

    upperArrayScores.forEach(idx => {
      if(idx !== undefined) {
        totalUpperScore += idx
      }
    })


    if(upperArrayScores.every(idx => idx !== undefined)) {
      //if the total is more than 63, apply bonus of 35 otherwise 0

       this.setState(st => ({
        scores: { ...st.scores, upperBonusScore: totalUpperScore >= 63 ? 35 : 0},
      }));

      } 

  }

Upvotes: 0

Views: 67

Answers (1)

Akhil Aravind
Akhil Aravind

Reputation: 6130

Here this.applyUpperScoreBonus() is called after the setState, since the setState({}) is async, this.applyUpperScoreBonus() only get state update on next doScore() call

This is your code block

if (this.state.scores[rulename] === undefined) {
      this.setState(st => ({
        scores: { ...st.scores, [rulename]: ruleFn(this.state.dice)},
        rollsLeft: NUM_ROLLS,
        locked: Array(NUM_DICE).fill(false)
      }));

      this.applyUpperScoreBonus();
      this.roll();

    }

Change it to

if (this.state.scores[rulename] === undefined) {
          this.setState(st => ({
            scores: { ...st.scores, [rulename]: ruleFn(this.state.dice)},
            rollsLeft: NUM_ROLLS,
            locked: Array(NUM_DICE).fill(false)
          }),()=> this.applyUpperScoreBonus()); // update here

          this.roll();

        }

Here, this.applyUpperScoreBonus() is called on setState() callback, so the function will get the updated state value.

Upvotes: 1

Related Questions