0

I've been using React on a personal project (simple card game). I call setState within my React component to change its state parameters, and I can verify through the console that some of the changes are made. However, the UI doesn't change at all. I'm wondering why changing the component's state doesn't seem to trigger its render method.

Specifically, the contents of this.state.hand are successfully changed by adding a card to the hand in the dealCard method (specifically by replacing the old hand with a new hand that contains the new card). However, additional updates to the hand's top and bottom scores are not made. Meanwhile, the UI is completely static even though this.state.hand was changed.

I've tried using the spread operator to make a shallow copy of this.state.hand, like the below. This doesn't work for me--it fails to add the new card to this.state.hand.

dealCard(card){
    const new_state = [...this.state.hand];
    new_state.push(card);
    this.updateState(this.state.hand, new_state);

Here is my code as of now:

class D9Hand extends React.Component {
  constructor(card1, card2){
    super([card1, card2]);
    this.state = {hand: [card1, card2], 
                  top_score: 0, 
                  btm_score: 0};
    this.MAX_CARDS_IN_HAND = 3;
    this.updateState = this.updateState.bind(this);
  };
  
  updateState(param, new_val){
    this.setState({param: new_val});
  }
  
  dealCard(card){
    let new_state = this.state.hand;
    new_state.push(card);
    this.updateState(this.state.hand, new_state); //state changed!
    this.countTopRow();                           //not updating scores!
    this.countBtmRow();
    console.log(this.state.hand, this.state.top_score, this.state.btm_score);
  };
  
  flip(card){
    card.flip();
    let new_state = [];
    for (const old_card of this.state.hand){
      if ((old_card.value_1 === card.value_2) && (old_card.value_2 === card.value_1)){
        new_state.push(card);
      } else {
          new_state.push(old_card);  
        };
    };
    this.updateState(this.state.hand, new_state); //state changed!
    this.countTopRow();                           //still not updating scores!
    this.countBtmRow();
    console.log(this.state.hand, this.state.top_score, this.state.btm_score);   
  };

  countTopRow() {
    let count = 0;
    for (const card of this.state.hand){
      count += card.value_1;
    };
    this.updateState(this.state.top_score, count % 10);
    return count % 10;
  };

  countBtmRow() {
    let count = 0;
    for (const card of this.state.hand){
      count += card.value_2;
    };
    this.updateState(this.state.btm_score, count % 10);
    return count % 10;
  };

  //other methods omitted for brevity's sake

  render(){
    return (
      <div className="hand">
      {this.state.hand.map(card => {
          return (
          <div>
            <div className="card">card</div> 
            <button className="button" onClick ={() => this.flip(card)}>{this.getFlipBtnText(card)}</button>
          </div>
          )  
      })}
        <div className="score-column">
          <div className="score">{this.countTopRow()}</div>
          <div className="score">{this.countBtmRow()}</div>
        </div>
      </div>
    );
  };
}

1 Answers1

0

state update in react not take place immediately,to overcome this you can pass call back function to react set state ,which will be called exactly after state change take place,so what i will suggest is ,instead of calling this.countTopRow(); after update state, you can pass a cllback function to updateSTate ,which will be passed to setState function from update state function like this

updateState(param, new_val,callback){
  if(callback){
    this.setState({param: new_val},callback);
  }else{
      this.setState({param: new_val});
  }

}

now your flip(card) function should look like this

 flip(card){
    card.flip();
    let new_state = [];
   for (const old_card of this.state.hand){
  if ((old_card.value_1 === card.value_2) && (old_card.value_2 === card.value_1)){
    new_state.push(card);
  } else {
      new_state.push(old_card);  
    };
};
this.updateState(this.state.hand, new_state,()=>{
   this.countTopRow();
   this.countBtmRow();
 });
 };

read more here

Jatin Parmar
  • 2,759
  • 5
  • 20
  • 31
  • Thanks for answering! I tried your suggestion, but it's still not re-rendering. But I'm thinking maybe the problem is somewhere else. – m_nt_s_no Sep 05 '22 at 16:54