1

I've got a very simple program that I've written to highlight an issue I'm faced with. I've currently got an array of objects where each object simply has a sequence number. On a button click, the first object will have its sequence number updated to increase by one.

In my program, I've got a couple of console logs to highlight my issue. First, I've initialised state to include the array of objects. I've then created a clone of that state, so that I can modify it, then setting the state back with the cloned (modified) object.

My program is as follows: App.tsx

import {useState} from 'react';

function reorder(questionData: Array<any>, count: number) {
  let finalQuestions = JSON.parse(JSON.stringify(questionData))
  console.log("finalQuestions before changes: ", finalQuestions)
  finalQuestions[0]['sequence'] = count
  return finalQuestions
}

function App() {
  const [questions, setQuestions] = useState([
    {
      sequence: 1
    },
    {
      sequence: 2
    },
    {
      sequence: 3
    }
  ])
  const [count, setCount] = useState(4)

  function change(questions: Array<any>, count: number) {
    console.log("questions before changes: ", questions)
    const finalQuestions = reorder(questions, count)
    setQuestions(finalQuestions)
    setCount(count+1)
    console.log("finalQuestions after changes: ", finalQuestions)
  }
  return (
    <div>
      <button onClick={() => change(questions, count)}>Click</button>
      <h1>Hello World</h1>
    </div>
  )
}

export default App

The issue I've got is that finalQuestions in the reorder function contains the updated values when I console log using console.log("finalQuestions before changes: ", finalQuestions). At this point, I'm expecting that this array of objects will be exactly like the original array of objects in console.log("questionData before changes: ", questionData) because I have not modified it. However, that is not the case.

To put it in hopefully easier terms, the following is the console logs after the first button click:

enter image description here

As you can see, questionData contains the original state but why is finalQuestions getting updated before finalQuestions[0]['sequence'] = count is even executed? I would only expect that to be the case in the 'after changes' console log, i.e. console.log("finalQuestions after changes: ", finalQuestions)

This may have something to do with React that I don't understand, but any help would be appreciated.

EDIT: Thank you all to the answers. I now understand that it's merely the console log that is displaying the reference rather than the actual value at the given time.

However, I've now modified my change function to output the original state after it is set with the cloned data, but it's showing as the un-modified data (opposite to my original issue, so to speak).

For example, this is the new method:

function change(questions: Array<any>, count: number) {
    console.log("questions before changes: ", questions)
    const finalQuestions = reorder(questions, count)
    setQuestions(finalQuestions)
    setCount(count+1)
    console.log("questions after changes: ", questions)
    console.log("finalQuestions after changes: ", finalQuestions)
  }

The console.log("questions after changes: ", questions) displays the original data set, rather than the modified one, which is what I'd expect following setQuestions(finalQuestions) (see screenshot below). How can I console log the actual state at that moment in time?

enter image description here

Adam
  • 2,384
  • 7
  • 29
  • 66

3 Answers3

1

After trace value changes, This is excepted result, and you are do it correctly, but only one thing is missing, theirs maybe bug on save reference on browser for console log, which its will print new value in browser log for each object is print and has a sequence like your case, to can view a real value, just put in your code for console this syntax:

  console.log(
    "finalQuestions before changes: ",
    JSON.parse(JSON.stringify(finalQuestions))
  );

and you must put it direct in console, not saved in variable...

Demo from here.

Also, I think this url will help you to discover this case.

Anees Hikmat Abu Hmiad
  • 3,460
  • 2
  • 19
  • 36
  • Thank you for that! I have edited my answer with a similar issue with regards to the original state not console logging correctly (I believe). Could you please have a look? – Adam May 10 '21 at 01:22
  • You are welcome, now this is excepted result, since the quastions param not updated now, you are setQuestions and thats true, but react still not re-render it again, its will re-render again onNext click... – Anees Hikmat Abu Hmiad May 10 '21 at 01:27
  • Thank you again. So even though it's displaying the "old" data because it hasn't yet re-rendered, the data itself is actually updated? – Adam May 10 '21 at 01:31
1

What's happening here is that console.log is an async function, which will store the reference to the array and when printing out that stored object has already been changed. This might vary depending on the devtool you are using.

More about this here:

  1. https://stackoverflow.com/questions/23392111/console-log-async-or-sync#:~:text=If%20this%20was%20async%2C%20I,though%20it%20is%20running%20synchronously.
  2. Is Chrome's JavaScript console lazy about evaluating arrays?
  • Thank you for that! I have edited my answer with a similar issue with regards to the original state not console logging correctly (I believe). Could you please have a look? – Adam May 10 '21 at 01:22
  • Again, setQuestions is async, that's why you are printing out the old values. I might be wrong here, but as javascript is single thread React will first need to finish running the whole function before any state updates. Hence, until the whole function is not completed, you will still have the old questions value. – Baltasar Solanilla May 10 '21 at 01:46
  • Thank you again for that! That makes sense and is quite in line with the other answer. The only reason I'm accepting the other answer as the correct one is because he had answered first. Both answers are the same. – Adam May 10 '21 at 01:52
0

The console log uses the reference of the object, So it will update the value when it is changed.

Try the below code.

console.log("finalQuestions before changes: ",JSON.stringify(finalQuestions));
Robin
  • 159
  • 6