Royi Levy
Royi Levy

Reputation: 631

React - useState not updating when used inside of useEffect

In my project, I want to save all console.log's in an array. I created a simple example that represents what I am trying to do.

  1. A simple button that when pressed - logs to the console.
  2. An array for all logged messages
  3. An useEffect hook that overrides the console.log function.

However, the array doesn't get bigger than 1 item.

The code:

import { useState, useEffect } from "react";

export default function App() {
  const [myLogs, setMyLogs] = useState<any[]>([]);

  useEffect(() => {
    var log = console.log;
    console.log("from useEffect");
    console.log = function () {
      var args = Array.prototype.slice.call(arguments);
      log.apply(this, args);
      setMyLogs({ ...myLogs, ...args });
    };
  }, []);

  return (
    <div>
      <button onClick={() => console.log("clicked :)")}>Click to Log</button>
      <p>{myLogs.toString()}</p>
    </div>
  );
}

Codesanbox link

I tried adding myLogs as a dependency to the useEffect hook thinking it might help but it just created an infinite loop. (This part I understand)

Upvotes: 1

Views: 761

Answers (2)

Drew Reese
Drew Reese

Reputation: 203512

The issue is that of a stale enclosure of initial myLogs state and also that of mutating the state invariant from array to object type.

Use a functional state update to correctly update from any previous state and not the state value closed over in callback scope. Maintain the array state invariant.

useEffect(() => {
  const log = console.log;
  console.log("from useEffect");
  console.log = function () {
    const args = Array.prototype.slice.call(arguments);
    log.apply(this, args);
    setMyLogs(myLogs => [...myLogs, args]);
    // or [...myLogs, ...args] if you want all the log args flattened
  };
}, []);

Upvotes: 3

Rahul Sharma
Rahul Sharma

Reputation: 10111

you are setting log as the object it should be an array. and correct way of doing this is below

setMyLogs((prev) => [ ...prev, ...args ]);

Upvotes: 2

Related Questions