I'm trying to make a simple setInterval function for a typing game but it keeps glitching out depending on my syntax or not updating at all as it is now.
How do I get this to update every second and call the functions in the if statement?
const [counter, setCounter] = useState(10);
useEffect(() => {
let timer = setInterval(() => {
setCounter(counter - 1);
if (counter === 0) {
setWordIndex(wordIndex + 1);
setLives(lives - 1);
life.play();
setCounter(10);
}
}, 1000);
}, []);
*********Edit***************
This is what I have now that is working. The first answer fixed the async issue of the counter not decrementing but I had to move the if statement outside of the useEffect to correct what I believe was caused by this same problem.
useEffect(() => {
let timer = setInterval(() => {
setCounter( counter => counter - 1);
}, 1000);
}, []);
if (counter == 0) {
setWordIndex(wordIndex + 1);
setLives(lives - 1);
life.play();
setCounter(10);
}
I'm trying to make a simple setInterval function for a typing game but it keeps glitching out depending on my syntax or not updating at all as it is now.
How do I get this to update every second and call the functions in the if statement?
const [counter, setCounter] = useState(10);
useEffect(() => {
let timer = setInterval(() => {
setCounter(counter - 1);
if (counter === 0) {
setWordIndex(wordIndex + 1);
setLives(lives - 1);
life.play();
setCounter(10);
}
}, 1000);
}, []);
*********Edit***************
This is what I have now that is working. The first answer fixed the async issue of the counter not decrementing but I had to move the if statement outside of the useEffect to correct what I believe was caused by this same problem.
useEffect(() => {
let timer = setInterval(() => {
setCounter( counter => counter - 1);
}, 1000);
}, []);
if (counter == 0) {
setWordIndex(wordIndex + 1);
setLives(lives - 1);
life.play();
setCounter(10);
}
Share
Improve this question
edited Jan 7, 2020 at 3:51
dnolan
asked Jan 7, 2020 at 3:18
dnolandnolan
431 silver badge5 bronze badges
2
- Remember to reconsult the useState docs every now and then. – Mike 'Pomax' Kamermans Commented Jan 7, 2020 at 3:24
- Does this answer your question? setInterval in a React app – Emile Bergeron Commented Jan 7, 2020 at 3:28
3 Answers
Reset to default 2Use callback function in setCounter
function. As you are calling the state update in an async function. it's good practice to update the state based on the previous state.
const [counter, setCounter] = useState(10);
useEffect(() => {
let timer = setInterval(() => {
setCounter(counter => {
const updatedCounter = counter - 1;
if (updatedCounter === 0) {
setWordIndex(wordIndex + 1);
setLives(lives - 1);
life.play();
return 10;
}
return updatedCounter;
}); // use callback function to set the state
}, 1000);
return () => clearInterval(timer); // cleanup the timer
}, []);
The previous answers aren't considering the counter values aren't immediately updating. They are also prone memory leaks since setInterval isn't cleared.
const [counter, setCounter] = useState(10);
useEffect(() => {
let timer = setInterval(() => {
setCounter( counter => {
const nC = counter - 1;
if (nC === 0) {
setWordIndex(wordIndex + 1);
setLives(lives - 1);
life.play();
return 10;
}
return nC;
});
}, 1000);
return () => clearInterval(timer);
}, []);
The previous answers weren't considering other states - wordIndex and lives and didn't include clear Intervals
It's advisable to use callback setState inside setIntervals and clear the interval on next useEffect call
const [counter, setCounter] = React.useState(10);
React.useEffect(() => {
let timer = setInterval(() => {
// It's advisable to use callback setState inside setIntervals
setCounter(prev => {
if (prev !== 0) return prev - 1;
setWordIndex(wordIndex + 1);
setLives(lives - 1);
life.play();
return 10;
});
}, 1000);
// And clear the interval next useEffect call
return () => clearInterval(timer);
}, [wordIndex, lives]);