Reputation: 631
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.
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>
);
}
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
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
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