1

I'm trying to figure out how to trigger setTimeout in React.

I'm pretty new to React and was taking a look at the documentation & "tic-tac-toe" guide. I modified the code from the guide and I wanted to reset the state to initial values after 3 seconds from finding the winner of the game.

The only information I could find was to use setTimeout in component's lifecycle, but in my case I don't want to setTimeout if the component was mounted. I would like to trigger it it's after calculateWinner() returns a truthy value.

Is it possible to achieve something like this in react or in order to do so should I restructure my app/components architecture?

Heres' my example: https://codesandbox.io/s/6l607x80r

Most of the stuff is happening in Board component, where I've created a countDown() function, but I'm not sure how to trigger it.

3 Answers 3

3

you can use the componentDidUpdate lifecycle like this:

componentDidUpdate() {
  if (calculateWinner(this.state.squares)) {
    this.countDown();
  }
}

also, you will need to change your countDown function:

setTimeout(() => {
  this.setState({
      squares: Array(9).fill(null),
      xIsNext: true,
    })
  }, 3000);
Sign up to request clarification or add additional context in comments.

Comments

1

First, you setTimeout first argument needs to be a function and so you would write

countDown() {
    setTimeout(() => this.setState({
      squares: Array(9).fill(null),
      xIsNext: true,
    }), 3000);
  }

Secondly, since you are calculating winner in render function, you would add another state variable to keep track of the countdown and then trigger countdown in render like

const winner = calculateWinner(this.state.squares);
let status;
if(winner && !this.state.isCounting) {
  this.countDown();
}

and countdown will look like

countDown() {
    this.setState({isCounting: true});
    setTimeout(() => this.setState({
      squares: Array(9).fill(null),
      xIsNext: true,
      isCounting: false
    }), 3000);
  }

Working demo

3 Comments

I don't think it's good practice to change state in render function, it should be done for example in componentDidUpdate lifecycle
yup, react complained about that in the console.
Sure componentDidUpdate is better place
0

So far I've come up two ways to do it.

Changing the countdown function to bind to (this) and then putting a return in the if(winner) statement that contains the html and the timer.

countDown()
{
    setTimeout
    (
        function()
        {
            this.setState
            ({
                squares : Array(9).fill(null),
                xIsNext : true,
/*//old----------------------------------------------------------------
            }),
            3000
        );
*///-------------------------------------------------------------------
            });
        }
        .bind(this),
        3000
    );
}

And I changed the if winner to this.

if(winner)
{
    status = 'Winner: ' + winner;
// Old code doesn't contain a return here.-----------------------------
    return(
            <div>
                <div className="status">{status}</div>
                <div className="board-row">
                    {this.renderSquare(0)}
                    {this.renderSquare(1)}
                    {this.renderSquare(2)}
                </div>
                <div className="board-row">
                    {this.renderSquare(3)}
                    {this.renderSquare(4)}
                    {this.renderSquare(5)}
                </div>
                <div style={{ marginBottom: 30 }} className="board-row">
                    {this.renderSquare(6)}
                    {this.renderSquare(7)}
                    {this.renderSquare(8)}
                </div>
                <Button id="reset" onClick={this.reset}>
                    Reset
                </Button>
// Call counDown(this) after the button.-------------------------------
                {this.countDown(this)}
            </div>
    )
}
else
{
    status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
}

The other way I was able to get it to work was to add setTimeout() in if(winner)

if(winner)
{
    status = "Winner: " + winner;
// Just add setTimeout() and it will reset after 3 seconds.------------
    setTimeout
    (
        ()=>
        {
            this.setState
            ({
                squares : Array(9).fill(null),
                xIsNext : true
            });
        },
        3000
    );
}
else
{
    status = "Next player: " + (this.state.xIsNext ? "X" : "O");
}

Here is an EXAMPLE

I've been playing with getting a countdown timer to display and will add it if I get it done later.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.