Hello guys I started learning react recently and I'm having some problems. I'm trying to make simple react app, one of the components I'm making is stopwatch. Now I'm having problem using props that I passed to my Stopwatch component from my parent component. This is my app component:
import React, {Component} from 'react';
import { Form,FormControl, Button} from 'react-bootstrap';
// Compoenents
import Clock from './Clock';
import Stopwatch from './Stopwatch';
// CSS
import './css/app.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
deadline: 'December 31, 2017',
newDeadline: '',
timer: 60,
newTimer: ''
}
}
changeDeadline () {
this.setState({deadline: this.state.newDeadline});
}
checkTimer() {
this.setState({timer: this.state.newTimer});
}
render() {
return (
<div className='app'>
<div className='appTitle'>
Countdown to {this.state.deadline}
</div>
<Clock
deadline={this.state.deadline} // This is how we send props to our child component
/>
<Form inline={true} >
<FormControl
className='deadlineInput'
type="text"
placeholder='Write date to check'
onChange={event => this.setState({newDeadline: event.target.value})}
onKeyPress={event => {
if(event.key === 'Enter') {
event.preventDefault();
this.changeDeadline();;
}
}}
/>
<Button
onClick={() => this.changeDeadline()}
>
Submit
</Button>
</Form>
<div className='stopwatchTitle'>
Use stopwatch to {this.state.timer} seconds
</div>
<Stopwatch
timer={this.state.timer} // This is how we send props to our child component
/>
<Form inline={true} >
<FormControl
className='timerInput'
type="text"
placeholder='Set your timer'
onChange={event => this.setState({newTimer: event.target.value})}
onKeyPress={event => {
if(event.key === 'Enter') {
event.preventDefault();
this.checkTimer();;
}
}}
/>
<Button
onClick={() => this.checkTimer()}
>
Start
</Button>
</Form>
</div>
)
}
}
export default App;
and this is my Stopwatch component:
import React, {Component} from 'react';
// CSS
import './css/stopwatch.css';
class Stopwatch extends Component {
constructor(props) {
super(props);
this.state = {
stopWatch: 0,
}
this.decrementer = null;
}
// This function runs before component completely renders on the application (otherwise we might create infinite loop)
componentWillMount() {
this.startTimer(this.props.timer);
}
startTimer(timer) {
let stopWatch = timer;
console.log(stopWatch)
this.decrementer = setInterval( () =>
this.setState({
stopWatch: this.state.stopWatch - 1
})
, 1000);
}
render() {
return (
<div>
<div className='myStopwatch'> {this.state.stopWatch} seconds</div>
</div>
)
}
}
export default Stopwatch;
Right now App always starts counting from 0 and goes into minus. How can I use my timer props that I pass down from my parent to my child component ? I want my stopwatch starting time be equal to my timer props. Also how to make countdown stop when it reaches 0 ?
How can I use my timer props that I pass down from my parent to my child component ? I want my stopwatch starting time be equal to my timer props.
On startTimer(timer)
you pass the timer
to the stopWatch
variable, but you end up using this.state.stopWatch
to initialize your interval.
Since this.state.stopWatch
is always 0, you stopwatch will always begin on 0.
One way to achieve what you want is to initialize this.state.stopWatch
with the value you are receiving from props:
constructor(props) {
super(props);
this.state = {
stopWatch: props.timer
}
this.decrementer = null;
}
componentWillMount() {
this.startTimer(); // now you dont need to pass timer because is already in your local state
}
Also how to make countdown stop when it reaches 0 ?
To achieve this you need to clear the interval once the timer reaches 0. You might also want to check if stopWatch
is 0 to prevent starting the interval:
startTimer() {
if(!this.state.stopWatch) return; // check if stopWatch is 0
this.decrementer = setInterval( () => {
const stopWatch = this.state.stopWatch - 1;
this.setState({ stopWatch });
if(stopWatch < 1) clearInterval(this.decrementer); // clears interval one stopWatch reaches 0
}, 1000);
}