1

I am doing a random quote app and it seems like I am using react state wrong when I try to change the body background and text-box text color. The body background color is one step behind all the time and I want them to change to the same color simultaneously. Any idea what is wrong with my code? I just added here the class component that is doing the business.

P.S. I hope my code is not too hard to read, I am a beginner

class Quote extends React.Component {
  constructor() {
    super();
    this.state = {
      quote: [],
      author: [],
      apiData:[],
      color: ""
    };
    this.handleClick = this.handleClick.bind(this)
  }

  componentDidMount() {
    //Here I made an API call for this.state.apiData to get my quotes
  }
  
  handleClick(){

    var randomColor = '#'+Math.floor(Math.random()*16777215).toString(16);        //Here I get a random color


    function getRandNum(min, max){
      return Math.floor(Math.random()*(max-min)+min)          //Here I get a random number in the range of my API array length
    }
    let randomNum = getRandNum(0,this.state.apiData.length)


    this.setState({
      quote: this.state.apiData[randomNum].text,
      author: this.state.apiData[randomNum].author
      color: randomColor
    }) 
    
    document.body.style.backgroundColor = this.state.color;
 
    console.log(this.state.color)
  }
  
  render() {
    return (
      <div class="quote-box">

        <h1 style={{color: this.state.color}}> {this.state.quote}-"{this.state.author}" </h1>

        <button 
                onClick={this.handleClick} 
                class="change-button" 
                style={{color: "white", backgroundColor: this.state.color}}
        >Change
        </button>

      </div>
    );
  }
}
Robert B
  • 67
  • 5
  • 1
    Does this answer your question? [Why calling react setState method doesn't mutate the state immediately?](https://stackoverflow.com/questions/30782948/why-calling-react-setstate-method-doesnt-mutate-the-state-immediately) –  Sep 08 '20 at 18:49
  • Yes, I got it now. Thank you a lot ! – Robert B Sep 08 '20 at 19:18

1 Answers1

0

Because setState sets the states asynchronously (the background color of the body is updated before the color is updated in the states). You can pass a second parameter to setState method that will be called after the states are updated.

this.setState(
  {
    quote: this.state.apiData[randomNum].text,
    author: this.state.apiData[randomNum].author
    color: randomColor
  }, 
  () => document.body.style.backgroundColor = this.state.color
)

Or you can alternatively set the background color of the body with randomColor variable.

this.setState({
  quote: this.state.apiData[randomNum].text,
  author: this.state.apiData[randomNum].author
  color: randomColor
}) 

document.body.style.backgroundColor = randomColor;

Or you can use componentDidUpdate to detect the changes in states.

Rohit Sharma
  • 3,304
  • 2
  • 19
  • 34
  • But shouldn't it update state first and then the body to take the updated this.state.color? Because first i write the setState method and then the body.style ?? Why is happening like this ? – Robert B Sep 08 '20 at 19:14
  • Because setState is asynchronous inside event handlers. [More here](https://reactjs.org/docs/faq-state.html#when-is-setstate-asynchronous) – Rohit Sharma Sep 08 '20 at 19:17