ReactJS: Statements in Method Call not Executed in Sequence

When a list item is clicked, the modifyItem() is called to append a new string to the items array.

From the console logs, it seems that the items array had been modified before the push method (*** below) is even called?? The statements in the function are not executed in sequence?

Appreciate any help on this, thank you!

Console Log Output:
Items BEFORE modification
[“1. Click me and check console log”, “2. Placeholder”, “additonal text”] // ***

Items AFTER modification
[“1. Click me and check console log”, “2. Placeholder”, “additonal text”]

App.jsx

import List from './List'
import "../styles.css";

export default function App()
{
  const items = ['1. Click me and check console log', '2. Placeholder']

  function modifyItem()
  {
    console.log('Items BEFORE modification')
    console.log(items)
    items.push('additonal text')
    console.log('Items AFTER modification')
    console.log(items)
  }
  return (
    <div className="App">
      <ul>
        { items.map((item, index) =>
        {
          return <List key={index} id={index} modifyItem={modifyItem} text={item} />
        })}
      </ul>
    </div>
  );
}

List.jsx

function List(props)
{
  function modifyMe()
  {
    console.log('Start of ModifyMe')
    props.modifyItem(props.index)
    console.log('End of ModifyMe')
  }
  return <li onClick={ modifyMe } >{ props.text }</li>
}

Codesandbox link here

I guess you want to trigger re-render whenever items has changes, correct?

In order to do that you need to use state, like so:

// setItems is a function that will set a new state triggering a re-render
const [items, setItems] = React.useState([
    "1. Click me and check console log",
    "2. Placeholder"
  ]);

Then it looks like you want to append item on click, right?

function appendItem() {
  // we will cal setItems to set a new state of our App
  setItems(items.concat(`${items.length + 1}. Additonal text`));
}

Then you want to pass this appendItem function to children:

<List key={index} appendItem={appendItem} text={item} />

Then in the List.js you want to call this function onClick for some reason, right?

function List({ text, appendItem }) {
  return <li onClick={appendItem}>{text}</li>;
}

Is this what you meant? If yes, hopefully this :point_up: would help

Snigo, thank you very much for the informative reply. I was able to re-render with useState() hook, however what I would like to understand was why the items array was modified even before the push() method was called.

As shown in the console logs, the value of items array was [“1. Click me and check console log”, “2. Placeholder”, “additonal text”] , before the push(‘additional text’) was called. In other words, the value of the items array was the same before and after the push() was called.

If the statements are executed in sequence, I would expect the results to be :

Console log output:

Items BEFORE modification
[“1. Click me and check console log”, “2. Placeholder”]

Items AFTER modification
[“1. Click me and check console log”, “2. Placeholder”, “additonal text”]

1 Like

Because you were logging array and not the snapshot of the array at that time. You can think of it as logging a “link” to array rather than state - it’s default behaviour of console log. So whenever you modify items it cascades to previous logs.

In order to log a snapshot of the object you need to turn it to a string, for example with JSON.stringify(items).

Does that mean the console.log() was executed after the push() method was called even though the console.log was above the push() method call? Is this behavior pertaining to JSX or React? Cos in vanilla JS, I would get the expected output.

Thanks!
Eg.

function testArrFn() {
  let tempArr = [1, 2, 3]

  console.log(tempArr) //output [1, 2, 3] and not [1, 2, 3, 4]
  tempArr.push(4)
  console.log(tempArr) //output [1, 2, 3, 4]

}

testArrFn()

React DevTools tends to cause this, because it triggers multiple rerenders, meaning side effects that are outside of the control of React (eg console.log) can appear to occur out of order. As @snigo says, you can’t do what you’re trying to do anyway outside of React’s state handling, so it’s a moot point, but yes, afaik it is React/React tooling causing this behaviour. I suspect (not tested) that if you generate a production build of your code it won’t log out of order (to test this you’d need to move your code to your machine then produce a build, probably using Create React App or similar).

Thank you for all the replies.