Shan Dou
Shan Dou

Reputation: 3278

Why does setState cause too many re-rendering when pushing a new element to an array state?

I have a code that listens to a server-side event, grabs the event data as object, and pushes it to a state array. However, at the moment I am directly updating the array instead of setting the state via setState. Otherwise, I'd get a "too many re-rendering" error.

const App = () => {
  const [records, setRecords] = useState([]);
  console.log(records);
  const newRecord = useDataListener({
    eventName: "message",
    srcURL: "http://localhost:5001/status_stream"
  });

  // If change into the following lines, code won't work
  // if (newRecord !== null) {
  //   setRecords(oldRecords => [newRecord, ...oldRecords])
  //}

  // But this looks incorrect, despite being able to render content
  if (newRecord !== null) {
    records.unshift(newRecord);
  }

  return (
    <div className="ui container">
      <Header />
      <PaginationBar />
      {records.map((x, i) => (
        <SummaryLog key={records.length - (i + 1)} record={x} />
      ))}
    </div>
  );
};

Does anyone see why using setRecords could cause too much re-rendering? Thanks!!

Upvotes: 1

Views: 543

Answers (2)

Joseph D.
Joseph D.

Reputation: 12174

Do not mutate the records. State should be immutable.

Also, fetching data is a side effect. So use useEffect hook to handle side effects.

useEffect(
  () => {
    setRecords(oldRecords => ([...oldRecords, newRecord]))
  }
  , [newRecord]
);

This hook will only run if there are newRecords.

Upvotes: 1

user9408899
user9408899

Reputation: 4540

Try using useEffect hook with newRecord dependency.

useEffect(() => {
   setRecords(oldRecords => [...oldRecords, newRecord])
  }, [newRecord]);

Upvotes: 1

Related Questions