0

I have a callback function from a table object where I was debugging some data and wanted to console.log the table object before it was updated with this.setState(). Now, I know this.setState is async, but I still expected to see the pre-update log, but instead it showed up post-update.

Here's the callback function:

onCellChange = (tableId, rowIdx, cellIdx) => e => {
    const value = parseFloat(e.target.value);
    console.log("TableID:", tableId);
    console.log(tableData); //This prints the tableData object post-this.setState()
    const tableTuple = { rowIdx, cellIdx, value, tableData, tableId };

    this.setState({
      tableData: updateInput(tableTuple)
    });
};

To test this, I commented out the this.setState call and tried again and the console.log() would print the pre-update value as expected since it's not going into the updateInput method anymore. It makes sense, but then I am not sure how to get the pre-update console.log value.

Javia1492
  • 862
  • 11
  • 28
  • 2
    `updateInput` probably mutates the Object. The console references an Object and reflects any modification that it receives. – Emile Bergeron Nov 21 '19 at 17:50
  • To sum it up; 1. Don't mutate state in updateInput function and 2. Console log the json instead of the object: `console.log(JSON.stringify(tableData))` – HMR Nov 21 '19 at 17:55
  • I can't see when the value of tableData object is set. Shouldn't you write console.log(this.state.tableData) instead? – Sylvain Nov 21 '19 at 17:56
  • About mutating the state, here's [why you shouldn't do it or be careful when updating the state to avoid accidental mutation](https://stackoverflow.com/a/37760774/1218980). – Emile Bergeron Nov 21 '19 at 18:27
  • @EmileBergeron Well, would passing the state object as a parameter still modify the original state? I assumed it would only modify the parameter itself and not the original. Otherwise, without this.setState, I would see the changes reflected, however, when I comment it out, I do not see the state updating. – Javia1492 Nov 21 '19 at 18:47
  • @Javia1492 [objects in JS are only referenced by variables](https://stackoverflow.com/q/37290747/1218980), so the parameter is just a reference to the same state object. – Emile Bergeron Nov 21 '19 at 19:02
  • [Why is immutability so important (or needed) in JavaScript?](https://stackoverflow.com/q/34385243/1218980) [How to update nested state properties in React](https://stackoverflow.com/q/43040721/1218980) [Whats the best way to update an object in an array in ReactJS?](https://stackoverflow.com/q/28121272/1218980) – Emile Bergeron Nov 21 '19 at 19:05

1 Answers1

4

On the browser, console.log allows you to interactively inspect the objects which are printed out. It does this by keeping a reference to the object it is given, and when the value at that reference changes, the console will reflect those updates, even in past logs.

Because of that, your console is showing you the state of tableData after it's been mutated. (Thanks to Emile Bergeron for clarifying this).

You can avoid this by logging a clone of your object, like so:

const tableDataCopy = { ...tableData };
console.log(tableDataCopy);

Or, if you can't use ES6, or you need a true deep copy, you can do

const tableDataCopy = JSON.parse(JSON.stringify(tableData));
console.log(tableDataCopy);
Michael Horn
  • 3,819
  • 9
  • 22
  • It's not slow, it's even explained in the console interface that the object is evaluated when expanded. – Emile Bergeron Nov 21 '19 at 17:59
  • Interesting... So, if I'm understanding you correctly, the console output in chrome can change _after_ it's already been displayed? I never knew that... – Michael Horn Nov 21 '19 at 18:01
  • I'm used to logging to a terminal, since I work with node a lot, and in that case that would be impossible of course – Michael Horn Nov 21 '19 at 18:02
  • I'm not sure it can change once evaluated, but it says _"Object value at left was snapshotted when logged, value below was evaluated just now."_, here's [an answer that explains it.](https://stackoverflow.com/a/23429304/1218980) – Emile Bergeron Nov 21 '19 at 18:05
  • Instead of adding **EDIT** sections to your answer, just remove anything that you'd like to reformulate, Stack Overflow has an edit history interface where we could look into to understand the comments were leaving here. – Emile Bergeron Nov 21 '19 at 18:07
  • In that case what I said actually holds, right? console.log is asynchronous because it is slow. The value given may be evaluated immediately, but if the value is a pointer, then that doesn't matter, because the object being referenced can change before the log actually occurs – Michael Horn Nov 21 '19 at 18:09
  • It's still not slow. If you're logging a copy (deep, or serialized as JSON), it will be available immediately. Though it's interactive, and with the nature of JS where objects are references (not exactly but close enough), the console can inspect nested references later on when the user expands them. – Emile Bergeron Nov 21 '19 at 18:13
  • Ah got it - Thanks, I've updated my answer – Michael Horn Nov 21 '19 at 18:20
  • 1
    Also note that once expanded, it looks like Chrome does a shallow copy, so the changes are no longer reflected. – Emile Bergeron Nov 21 '19 at 18:23