1

I am building a simple stopwatch app in ReactJS (count down to 0). So far I have an input where the user can set how long the timer should be and a button which updates the timer state with the input data. However I am not able to have the timer countdown, even with using setInterval().

App.jsx

import React, {Component} from 'react';
import Timer from './timer';
import './app.css';
import { Form, FormControl, Button} from 'react-bootstrap';

export class App extends Component {
    constructor(props) {
        super(props);
        this.state = {
            timerPosition: '',
            newTimerPosition: '',
          };          
    }

startTimer() {
    this.setState({timerPosition:this.state.newTimerPosition})
}

    render() {
        return (
        <div className="App-title"> Stopwatch </div>
        <Timer timerPosition={this.state.timerPosition} />
        <Form inline>
        <FormControl 
        className="Deadline-input"
        onChange={event => this.setState({newTimerPosition: event.target.value})}
        placeholder='Set timer'/>
        <Button onClick={() => this.startTimer()}>Set new timer</Button>
        </Form>
        </div>
        )}



}

export default App;

Timer.jsx

import React, {Component} from 'react';
import './app.css';

export class Timer extends Component {
    constructor(props) {
        super(props);
        this.state = {
        secondsRemaining: ''
         }
    }

componentWillMount(){
    this.startTimer(this.props.timerPosition);
}

componentDidMount(){
    setInterval(() => this.startTimer(this.props.timerPosition), 1000);
}


startTimer(timerCallback) {
    this.setState({secondsRemaining: timerCallback --})
}



render() { 
return (
<div>

<div></div>
{this.state.secondsRemaining} seconds remaining
</div>


)}

}


export default Timer;

The timer does not decrement every second and just stays at the original position.

1
  • Please reduce the code in your question to a minimal reproducible example demonstrating the problem, ideally a runnable one using Stack Snippets (the [<>] toolbar button). Stack Snippets support React, including JSX; here's how to do one. Commented Jan 1, 2018 at 19:17

2 Answers 2

2

The primary issue is in the interval callback in Timer's componentDidMount:

componentDidMount(){
    setInterval(() => this.startTimer(this.props.timerPosition), 1000);
}

Note that you're constantly reusing this.props.timerPosition as the timer position, instead of using the current state. So you're setting the state back to the initial state from the props.

Instead, you want to use the current state. How you use that state will depend on how you want the timer to behave, but beware of two things:

  1. Never call this.setState({foo: this.state.foo - 1}) or similar. State updates are asynchronous and can be combined. Instead, pass a callback to setState.

  2. Nothing is guaranteed to happen at any particular time or on a specific interval, so don't just decrement your counter; instead, see how long it's been since you started, and use that information to subtract from your initial counter value. That way, if your timer is delayed, you still show the correct value.

Sign up to request clarification or add additional context in comments.

Comments

0

The problem is you keep using the same prop value secondsRemaining. You decrement the same value in the propthis.props.timerPosition each time. So the state value secondsRemaining never changes.

Instead decrement the secondsRemaining value from state using the setState method which takes a callback. The first parameter of the callback is the current state. so you do:

this.setState((prevState, props) => {
    return { secondsRemaining: prevState.secondsRemaining - 1 };
  }); 

You also need to set your initial state value to the supplied props value:

componentWillMount(){
    this.setState({ secondsRemaining: this.props.timerPosition });
    ... other code
}

3 Comments

Thank you, it is counting down now, however it is ignoring the original state (timerPosition). So if I input something into the form (updating timerPosition), the secondsRemaining state is not updated. I would appreciate your further help.
You need to set up the initial state by setting state.secondsRemaining (using setState) from the supplied props value in componentWillMount. I'll update my answer
Unfortunately that didn't change anything

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.