Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is global variable executed twice in React

I'm a newbie on frontend development and learning React. Now I'm trying to build a hello-world project.

After executing npx create-react-app myapp, I got an initial React project and I just coded in the file App.js.

import React, {useState} from 'react';

var counter = 0;

function App() {
  const [counter2, setCount] = useState(0);
  const increment = () => {
    setCount(counter2 + 1);
  };
  
  return(
    <div>
      <button onClick= {increment}>Increment</button>
      <h1>{counter++}</h1> // 1, 3, 5, 7... WHY???
      <h1>{counter2}</h1>  // 0, 1, 2, 3...
    </div>
  );
}

export default App;

After executing npm start, I got my index page, which contains three parts: a button and two numbers.

To my surprise, when I click the button, counter2 is increased as expected, but counter is increased twice. Meaning that keeping clicking the button gives me the result as below:

1 0, 3 1, 5 2...

Why is the global variable counter increased two by two, instead of one by one?

Furthermore, what is the difference between React State and common global variable?

like image 270
Yves Avatar asked Aug 19 '26 18:08

Yves


1 Answers

When you wrap a component in <React.StrictMode>, it will run certain functions twice, one of these being the function body of your functional component:

This is done by intentionally double-invoking the following functions:

... Function component bodies

- React docs

This is only done in dev mode, and the idea behind doing it is to help you catch side-effects within your project.

It may seem as though your component is only being executed once though, as putting a console.log() inside of your functional component will only run once per state change. This is because, as of React 17, they have updated the console.log method to not log on the second invocation of your function:

Starting with React 17, React automatically modifies the console methods like console.log() to silence the logs in the second call to lifecycle functions

- React docs

However, there is a workaround to this by saving a reference to the console.log method, and using that to perform your logs. Doing this will allow you to see that your component is being executed twice:

const log = console.log;
function App() {
  const [counter2, setCount] = useState(0);
  const increment = () => {
    setCount(counter2 + 1);
  };
  log("Rendering, counter is:", counter);
  return(
    <div>
      <button onClick= {increment}>Increment</button>
      <h1>{counter++}</h1> 
      <h1>{counter2}</h1> 
    </div>
  );
}

The above will output the following when the component mounts, showing that the function body is running twice:

Rendering, counter is: 0
Rendering, counter is: 1

If you remove the <React.StrictMode> component then counter will increase by one each render, as React will no longer double-invoke your functional component body, and your component body will only be called once:

ReactDOM.render(<App />, document.getElementById('root'));

In terms of global variables vs state, the main difference has been pointed out in a comment above. That is that when you update your state with setMethodName(), you'll cause your component body to rerender, which doesn't happen when you update a normal variable as React won't be aware of the changes made to it.

like image 130
Nick Parsons Avatar answered Aug 21 '26 10:08

Nick Parsons