Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

setTimeout in react setState

this.setState(prevState => ({
    score:            prevState.score + 10,
    rightAnswers:     prevState.rightAnswers + 1,
    currentQuestion:  setTimeout(() => {
      prevState.currentQuestion + 1
    }, 2000)
    }))
  }

On button click I change the state. My goal is to have a delay in currentQuestion state change, during which I want to show certain status messages, yet I want to update the score right away without delays.

What's the proper way to do that?

PS: This variant doesn't work, it's for the overall representation of what I want to do.

Thanks.

like image 339
Happy Block Avatar asked Jun 25 '18 14:06

Happy Block


People also ask

How do you set setTimeout in React?

Using setTimeout in React Components We'll call setTimeout inside of the useEffect Hook, which is the equivalent of the componentDidMount lifecycle method in Class components. import React, { useEffect } from 'react'; const App = () => { useEffect(() => { const timer = setTimeout(() => { setCount('Timeout called!'

How do I add timeout in useEffect?

If we want to execute the timeout once when the component mounts, we need to use useEffect for that: useEffect(() => { const timer = setTimeout(() => console. log('Initial timeout!'

How do I clean up setTimeout in useEffect?

Use the useEffect hook to set up the timeout or interval. Return a function from the useEffect hook. Use the clearTimeout() or clearInterval() methods to remove the timeout when the component unmounts.

Is setTimeout asynchronous?

setTimeout() is an asynchronous function, meaning that the timer function will not pause execution of other functions in the functions stack.


2 Answers

You can do this multiple ways:

1) Make two calls to setState. React will batch any concurrent calls to setState into one batch update, so something like this is perfectly fine:

this.setState( prevState => ({
  score: prevState.score + 10,
  rightAnswers: prevState.rightAnswers + 1
}));

setTimeout( () => {
  this.setState( prevState => ({
    currentQuestion: prevState.currentQuestion + 1
  }));
}, 2000);

2) You can use the setState callback to update state after your first call is finished:

this.setState(prevState => ({
  score:            prevState.score + 10,
  rightAnswers:     prevState.rightAnswers + 1
}), () => {
  setTimeout( () => {
      this.setState( prevState => ({
      currentQuestion: prevState.currentQuestion + 1
    }));
  }, 2000);
});
like image 168
Chase DeAnda Avatar answered Sep 23 '22 05:09

Chase DeAnda


First use setState to change score and question with some value like null so that you know its updating and then also set timeout after that.

class Example extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      score: 1,
      question: "A"
    }
  }

  update() {
    this.setState(prev => ({
      score: prev.score + 1,
      question: null
    }));

    this.change = setTimeout(() => {
      this.setState({question: "B"})
    }, 2000)
  }

  render() {
    let {score, question} = this.state;
    let style = {border: "1px solid black"}
	
    return (
      <div style={style} onClick={this.update.bind(this)}>
        <div>{score}</div>
        <div>{question ? question : "Loading..."}</div>
      </div>
    )
  }
}

ReactDOM.render( < Example / > , document.querySelector("#app"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
like image 39
Nenad Vracar Avatar answered Sep 23 '22 05:09

Nenad Vracar