Hello guys I started learning react recently and I'm having some issues. I'm trying to make simple react app, one of the components I'm making is stopwatch.
The issue I'm having is that when I start typing in my input for stopwatch the timer resets.
Here is my main component:
import React, { Component } from 'react';
import Clock from '../components/Clock.jsx';
import Stopwatch from '../components/Stopwatch.jsx';
import '../css/App.css';
import { Form, FormControl, Button } from 'react-bootstrap';
class App extends Component {
constructor(props) {
super(props);
this.state = {
deadline: 'December 25, 2018',
newDeadline: '',
timer: 60,
newTimer: '',
};
}
changeDeadline() {
this.setState({
deadline: this.state.newDeadline,
});
}
changeTimer() {
this.setState({
timer: this.state.newTimer,
});
}
render() {
return (
<div className='app'>
<div className='app_title'>
Countdown to {this.state.deadline}
</div>
<Clock
deadline = {this.state.deadline}
/>
<Form inline >
<FormControl
className="deadline_input"
type="text"
placeholder="New date"
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="stopwatch_title">
Stopwatch from {this.state.timer} seconds
</div>
<Form inline>
<FormControl
className="stopwatch_input"
type="text"
placeholder="Enter time"
onChange={event => this.setState({newTimer: event.target.value})}
onKeyPress={event => {
if (event.key === 'Enter') {
event.preventDefault();
this.changeTimer();
}
}}
/>
<Button onClick={() => this.changeTimer()} >
Submit
</Button>
</Form>
<Stopwatch
timer = {this.state.timer}
/>
</div>
);
}
}
export default App;
and my stopwatch component:
import React, {Component} from 'react';
import '../css/App.css';
import { Button } from 'react-bootstrap';
class Stopwatch extends Component {
constructor(props) {
super(props);
this.state = {
stopwatch: props.timer,
};
this.decrementer = null;
}
componentWillReceiveProps(nextProps) {
clearInterval(this.decrementer);
this.timerCountdown(nextProps.timer);
}
timerCountdown(newTimer) {
// First we update our stopwatch with new timer
this.setState({
stopwatch: newTimer
});
}
startTimer() {
// Then we decrement stopwatch by 1 every second
this.decrementer = setInterval( () => {
this.setState({
stopwatch: this.state.stopwatch -1,
});
},1000);
}
componentDidUpdate() {
if (this.state.stopwatch < 1) {
clearInterval(this.decrementer);
alert('Countdown finished');
}
}
render() {
return(
<div>
<Button onClick={() => this.startTimer()} >
Start
</Button>
<div className="stopwatch"> {this.state.stopwatch} </div>
</div>
);
}
}
export default Stopwatch;
Here is gif of the problem https://imgur.com/9xqMW96
As you can see my timer resets after I start typing in input. I would like for it to reset only when user presses enter
key or uses submit
button.
I've tried doing something like this:
<input value={this.state.newTimer} onChange={evt => this.updateInputValue(evt)}/>
updateInputValue: function(evt) {
this.setState({
newTimer: evt.target.value
});
}
but it didn't work for me. You can see code in action here: https://karadjordje.github.io/countdown-stopwatch-react/
答案 0 :(得分:1)
You are stopping the interval
on each new prop that the component receives.
You can either handle the time in a local state
or explicitly pass the proper new values from the parent.
I've made a small basic example so you can see the data flow and how each event is responsible for a small portion of the data.
Hope that helps.
class App extends React.Component {
state = {
startTime: 5,
currentTime: 5,
textInput: ''
}
startTimer = () => {
if (this.interval) {
clearInterval(this.interval);
}
this.interval = setInterval(() => {
this.setState(prev => {
if (prev.currentTime === 0) {
this.stopTimer();
return { ...prev, currentTime: prev.startTime };
} else {
return {
...prev,
currentTime: prev.currentTime - 1
}
}
})
}, 1000)
}
stopTimer = () => {
clearInterval(this.interval);
}
updateInput = ({ target }) => {
this.setState(prev => ({ textInput: target.value }));
}
setStartTime = () => {
this.stopTimer();
this.setState(({ textInput }) => ({ startTime: textInput, currentTime: textInput, textInput: '' }));
}
render() {
const { currentTime, textInput } = this.state;
return (
<div >
<div>{currentTime}</div>
<button onClick={this.startTimer}>Start timer</button>
<div>
<input placeholder="Enter start time" value={textInput} onChange={this.updateInput} />
<button onClick={this.setStartTime}>Set Start time</button>
</div>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
<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="root"></div>
答案 1 :(得分:1)
我已更新了我的代码。
而不是使用componentWillUpdate
我使用componentDidUpdate
这是我的代码:
componentDidUpdate(prevProps) {
console.log('componentDidUpdate', this.props, prevProps);
if (prevProps.timer !== this.props.timer) {
this.updateTimer(this.props.timer);
clearInterval(this.decrementer);
}
if (this.state.stopwatch < 1) {
clearInterval(this.decrementer);
alert('Countdown finished');
}
}
基本上我只更新定时器,前一个定时器与当前定时器不同。