In my code I have some problems with intervals. I have situation like this
import { useState } from 'react';
function App() {
const [count, setCount] = useState(0);
function handleClick() {
const timer = setInterval(() => {
if (count >= 10) {
clearInterval(timer);
} else {
setCount((prevCount) => prevCount + 1);
}
}, 1000);
}
return (
<>
<button onClick={handleClick}>start</button>
<p>{count}</p>
</>
);
}
export default App;
what am trying to do is to start an interval when user click a button and stop it when counter reaches 10, but it never stops and debugger says that inside setInterval
count is always 0. Does anybody know what is the problem? I also found that if I rewrite component to class
component like this
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0,
};
}
handleClick() {
let myInterval = setInterval(() => {
if (this.state.count >= 10) {
clearInterval(myInterval);
} else {
this.setState((prevState) => ({
count: prevState.count + 1,
}));
}
}, 1000);
}
render() {
return (
<>
<button onClick={this.handleClick.bind(this)}>start</button>
<p>{this.state.count}</p>
</>
);
}
}
it works perfectly.
I don't know what's happening and I spend almost day trying to figure out.
So does anybody know why class
component works and why functional
component doesn't?
Thanks in advance
You can use the "ref boxing" pattern to have a readable reference to the latest value of the state atom:
import {useState, useRef} from 'react';
function App() {
const [count, setCount] = useState(0);
const countRef = useRef(null);
countRef.current = count; // Update the boxed value on render
function handleClick() {
const timer = setInterval(() => {
if (countRef.current >= 10) { // Read the boxed value
clearInterval(timer);
} else {
setCount((prevCount) => prevCount + 1);
}
}, 1000);
}
return (
<>
<button onClick={handleClick}>start</button>
<p>{count}</p>
</>
);
}
Note that you're currently not correctly cleaning up the timer on unmount, leading to React warning you about that when you'd unmount your app. The same holds for your class component.