Reputation: 2743
I have the following code, which I expect it to print an extra 10 every 2 seconds on the screen. However, it only prints 10 once. console.log(digits)
gave me the correct array of 10s. How can I add a 10 to the array every 2 seconds and print the updated array on the screen each time the 10 is added?
Code sandbox here: https://codesandbox.io/s/silly-https-zk58p?file=/src/App.js
import { useEffect, useState } from "react";
let data = [];
export default function App() {
const [digits, setDigits] = useState([]);
useEffect(() => {
let timer = setInterval(() => {
data.push(10);
setDigits(data);
console.log(digits);
}, 2000);
return () => clearInterval(timer);
}, [digits]);
return <div className="App">{digits}</div>;
}
Upvotes: 0
Views: 110
Reputation: 1325
The issue is with setDigits(data)
. With arrays, you should be executing setDigits([...data])
.
Another way would be doing this:
let timer = setInterval(() => {
setDigits([...digits, 10]);
}, 2000);
Whenever dealing with objects, you should treat them as immutables. What happened here is you modifying an array and puhsing the SAME array into a state. While the value might be different, the array is actually the same hence it does not update the render. Whenever doing [...data]
it creates a new array with the same values hence trigger the update.
useEffect
picks up the new value change hence why it fires again(cant be observed by console.log()
), but this does not trigger re-render of the component.
Upvotes: 1
Reputation: 1036
In your code, you are mutating the same array data
by pushing 10
after each 2
seconds. As a result, the useEffect
is not executing in the subsequent renders. So either you spread data
array as in the following code snippet or simply get rid of the data
variable and rely on digits
array as Lith suggested.
export default function App() {
const [digits, setDigits] = useState([]);
useEffect(() => {
let timer = setInterval(() => {
data = [...data, 10];
setDigits(data);
console.log(digits);
}, 2000);
return () => clearInterval(timer);
}, [digits]);
return <div className="App">{digits}</div>;
}
Upvotes: 1