I'm still fairly new at React, but I've been grinding along slowly and I've encountered something I'm stuck on.
I am trying to build a "timer" component in React, and to be honest I don't know if I'm doing this right (or efficiently). In my code below, I set the state to return an object { currentCount: 10 }
and have been toying with componentDidMount
, componentWillUnmount
, and render
and I can only get the state to "count down" from 10 to 9.
Two-part question: What am I getting wrong? And, is there a more efficient way of going about using setTimeout (rather than using componentDidMount
& componentWillUnmount
)?
Thank you in advance.
import React from 'react';
var Clock = React.createClass({
getInitialState: function() {
return { currentCount: 10 };
},
componentDidMount: function() {
this.countdown = setInterval(this.timer, 1000);
},
componentWillUnmount: function() {
clearInterval(this.countdown);
},
timer: function() {
this.setState({ currentCount: 10 });
},
render: function() {
var displayCount = this.state.currentCount--;
return (
<section>
{displayCount}
</section>
);
}
});
module.exports = Clock;
This question is related to
javascript
reactjs
settimeout
state
Updated 10-second countdown using class Clock extends Component
import React, { Component } from 'react';
class Clock extends Component {
constructor(props){
super(props);
this.state = {currentCount: 10}
}
timer() {
this.setState({
currentCount: this.state.currentCount - 1
})
if(this.state.currentCount < 1) {
clearInterval(this.intervalId);
}
}
componentDidMount() {
this.intervalId = setInterval(this.timer.bind(this), 1000);
}
componentWillUnmount(){
clearInterval(this.intervalId);
}
render() {
return(
<div>{this.state.currentCount}</div>
);
}
}
module.exports = Clock;
If anyone is looking for a React Hook approach to implementing setInterval. Dan Abramov talked about it on his blog. Check it out if you want a good read about the subject including a Class approach. Basically the code is a custom Hook that turns setInterval as declarative.
function useInterval(callback, delay) {
const savedCallback = useRef();
// Remember the latest callback.
useEffect(() => {
savedCallback.current = callback;
}, [callback]);
// Set up the interval.
useEffect(() => {
function tick() {
savedCallback.current();
}
if (delay !== null) {
let id = setInterval(tick, delay);
return () => clearInterval(id);
}
}, [delay]);
}
Also posting the CodeSandbox link for convenience: https://codesandbox.io/s/105x531vkq
Thanks @dotnetom, @greg-herbowicz
If it returns "this.state is undefined" - bind timer function:
constructor(props){
super(props);
this.state = {currentCount: 10}
this.timer = this.timer.bind(this)
}
Updating state every second in the react class. Note the my index.js passes a function that return current time.
import React from "react";
class App extends React.Component {
constructor(props){
super(props)
this.state = {
time: this.props.time,
}
}
updateMe() {
setInterval(()=>{this.setState({time:this.state.time})},1000)
}
render(){
return (
<div className="container">
<h1>{this.state.time()}</h1>
<button onClick={() => this.updateMe()}>Get Time</button>
</div>
);
}
}
export default App;
Manage setInterval with React Hooks:
const [seconds, setSeconds] = useState(0)
const interval = useRef(null)
useEffect(() => { if (seconds === 60) stopCounter() }, [seconds])
const startCounter = () => interval.current = setInterval(() => {
setSeconds(prevState => prevState + 1)
}, 1000)
const stopCounter = () => clearInterval(interval.current)
Updated 10-second countdown using Hooks (a new feature proposal that lets you use state and other React features without writing a class. They’re currently in React v16.7.0-alpha).
import React, { useState, useEffect } from 'react';
import ReactDOM from 'react-dom';
const Clock = () => {
const [currentCount, setCount] = useState(10);
const timer = () => setCount(currentCount - 1);
useEffect(
() => {
if (currentCount <= 0) {
return;
}
const id = setInterval(timer, 1000);
return () => clearInterval(id);
},
[currentCount]
);
return <div>{currentCount}</div>;
};
const App = () => <Clock />;
ReactDOM.render(<App />, document.getElementById('root'));
Source: Stackoverflow.com