Jimbo
Jimbo

Reputation: 45

React useState: Always rerenders when state is an array

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>
  );
}

Code sandbox

Upvotes: 0

Views: 250

Answers (2)

Omer Messer
Omer Messer

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

Taghi Khavari
Taghi Khavari

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

Related Questions