Here we got a strange problem. I'm a reactJs newbie and working on a simple Timer project. my code is like below:
import React, { useEffect, useState } from "react";
const TestTimer = () => {
const [seconds, setSeconds] = useState(10);
useEffect(() => {
let timer = setInterval(() => {
console.log(seconds);
setSeconds(function(seconds){
return seconds - 1;
});
}, 1000)
}, []);
return (
<div className="timer-component text-light">
{ seconds }
</div>
)
}
export default TestTimer;
The problem is, that in DOM we can see the change in seconds. every second passes, it goes down by 1.
But in the console, all I see is the same "10". It only prints 10 every seconds.
Where am doing it wrong? any help is appreciated.
Also I searched a lot about it but all problems are about "state being changed, but we have no change in DOM". Mine is completely vice versa!
CodePudding user response:
Because you have used console.log
inside setInterval callback, and actually this callback has access to the initial value of state, you can move your console.log
inside the state updater function and get the expected result, like this:
const TestTimer = () => {
const [seconds, setSeconds] = React.useState(10);
React.useEffect(() => {
let timer = setInterval(() => {
setSeconds(function(seconds){
console.log(seconds);
return seconds - 1;
});
}, 1000)
}, []);
return (
<div className="timer-component text-light">
{ seconds }
</div>
)
}
ReactDOM.render(<TestTimer/>, document.getElementById("root"))
<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<div id="root"></div>
CodePudding user response:
There's a couple issues:
Per your question, you're calling your console.log() inside the setInterval callback but outside of your state setter function. So this is only accessing your default value and then reprinting on every return.
let timer = setInterval(() => { setSeconds(function(seconds){ console.log(seconds); <------- Console here within state setter return seconds - 1; }); }, 1000)
Your code is updating by -2 every time useEffect is called. This is because you aren't cleaning up your useEffect call. It's good practice to always cleanup a function utilizing a timer within a useEffect or else you run into problems like so. Read more about useEffect https://reactjs.org/docs/hooks-reference.html#useeffect
Here's your example with a cleanup function and your intended results
useEffect(() => {
let timer = setInterval(() => {
setSeconds(function(seconds){
console.log(seconds);
return seconds - 1;
});
}, 1000)
return () => clearInterval(timer) <----- Cleanup function
},[]);