Reputation: 45
I have a React app where I have an array as a state. Then I have a timer that reads an array. Now I want to rerender only if there is a difference between the array I read and my state array.
But when I do as in the following code example it always rerenders. If I instead have a state with just a number, and set the same number, it will not rerender. Is there a way to achieve the same thing with an array? Or do I have to compare the arrays first, and then call setMeasData only if they are different?
A second question is why the rerenders variable is always increased by two the code sandbox? This does not happen in my real application, so that is not a big deal. Just curious.
Thanks!
let rerenders = 0;
function getMeas() {
return [{ name: "Measurement 1", value: 0 }];
}
export default function App() {
const [measData, setMeasData] = React.useState([
{ name: "Measurement 1", value: 0 }
]);
rerenders++;
console.log("Rerenders: " + rerenders);
React.useEffect(() => {
console.log("In useEffect");
const timer = setInterval(() => {
console.log("Timer triggered");
let newMeasData = getMeas();
// Want this to trigger rerender only if newMeasData is not the same as measData
setMeasData(newMeasData);
}, 10 * 1000);
return () => {
clearInterval(timer);
};
}, []);
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>No of rerenders: {rerenders} </h2>
<p>
{" "}
{measData[0].name}: {measData[0].value}{" "}
</p>
</div>
);
}
Upvotes: 0
Views: 250
Reputation: 33
regarding "A second question is why the rerenders variable is always increased by two the code sandbox?"
In development react always renders your component twice for debugging purposes, to make sure the functional component is "pure" https://react.dev/learn/keeping-components-pure https://react.dev/reference/react/StrictMode#fixing-bugs-found-by-double-rendering-in-development
Upvotes: 1
Reputation: 6582
That's because on every interval you're setting a new value to the setMeasData
and you can check this by using this operation:
console.log(getMeas() === getMeas()) // which always logs false
everytime getMeas
function is called it will return a new instance
and in React
when the state
is changed we're going to have a rerender
if you want to have just something to set the initialValue
you could do so by storing the value in a variable like below so you're instance always will be the same and you won't have extera rerenders:
let rerenders = 0;
const initialValue = [{ name: "Measurement 1", value: 0 }];
export default function App() {
const [measData, setMeasData] = React.useState(initialValue);
rerenders++;
console.log("Rerenders: " + rerenders);
React.useEffect(() => {
console.log("In useEffect");
const timer = setInterval(() => {
console.log("Timer triggered");
let newMeasData = initialValue;
// Want this to trigger rerender only if newMeasData is not the same as measData
setMeasData(newMeasData);
}, 1 * 1000);
return () => {
clearInterval(timer);
};
}, []);
return (
<div className="App">
<h1>Example</h1>
<h2>
No of rerenders: {rerenders} {`${initialValue === initialValue}`}{" "}
</h2>
<p>
{" "}
{measData[0].name}: {measData[0].value}{" "}
</p>
</div>
);
}
Upvotes: 1