Im creating a clock that has minutes and seconds. This is how my component looks like
class Time extends React.PureComponent
{
constructor(props)
{
super(props);
this.state =
{
hrs: 0,
mins: 0,
secs: 0
}
this.tick = this.tick.bind(this);
}
tick()
{
//This increments the minutes
if(this.state.secs >= 59)
{
this.setState({mins: this.state.mins 1});
this.setState({secs: 0});
}
//This increments the hours
if(this.state.minutes >= 59)
{
this.setState({hrs: this.state.hrs 1});
this.setState({mins: 0});
}
else
{
//This increments the seconds
this.setState({secs: this.state.secs 1});
}
}
componentDidMount()
{
this.tock = setInterval(()=>
{
this.tick();
}, 1000)
}
componentWillUnmount()
{
clearInterval(this.tock);
}
render()
{
return(
<div>
<h1>Time</h1>
<section>
{this.state.hrs}:{this.state.mins}:{this.state.secs}
</section>
</div>
);
}
}
}
export default Time;
The mins do increment to 59 and in turn increment the hrs - then reset to 0. But the secs just keep going and never reset to 0. They do update the mins though. The problem is that they go from 0 to infinity and dont stop counting. How can I make them reset to 0 each time?
CodePudding user response:
setState
is asynchronous, so you cannot ensure all the state updates in the sequence with multiple setState
. I'd suggest that you should have only one setState
at the end of that function after all secs
, mins
, and hrs
computed.
Side note I also fixed your wrong value in this.state.minutes
to this.state.mins
.
class Time extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
hrs: 0,
mins: 0,
secs: 0,
};
this.tick = this.tick.bind(this);
}
tick() {
let { secs, mins, hrs } = this.state;
secs = 1;
if (secs > 59) {
mins = 1;
secs = 0;
}
if (mins > 59) {
hrs = 1;
mins = 0;
}
this.setState({ secs, mins, hrs });
}
componentDidMount() {
this.tock = setInterval(() => {
this.tick();
}, 1000);
}
componentWillUnmount() {
clearInterval(this.tock);
}
render() {
return (
<div>
<h1>Time</h1>
<section>
{this.state.hrs}:{this.state.mins}:{this.state.secs}
</section>
</div>
);
}
}
CodePudding user response:
You could also use a functional based component to achieve the same effect.
function Time() {
const [time, setTime] = useState({
secs: 50,
mins: 58,
hrs: 0
});
const tick = () => {
setTime(prevState => ({...prevState, secs: prevState.secs 1}));
}
useEffect(() => {
setInterval(() => {
tick()
}, 1000)
}, []);
useEffect(() => {
if(time.secs > 59) {
setTime(prevState => ({ ...prevState, secs: 0, mins: prevState.mins 1 }));
}
}, [time.secs])
useEffect(() => {
if (time.mins > 59) {
setTime(prevState => ({ ...prevState, mins: 0, hrs: prevState.hrs 1 }));
}
}, [time.mins])
return (
<div>
<h1>Time</h1>
<section>
{time.hrs}:{time.mins}:{time.secs}
</section>
</div>
);
}
export default Time;