为什么全局变量在 React 中被执行了两次

Why is global variable executed twice in React

我是前端开发和学习 React 的新手。现在我正在尝试构建一个 hello-world 项目。

执行 npx create-react-app myapp 后,我得到了一个初始 React 项目,我只是在文件 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;

执行npm start后,我得到了我的索引页,它包含三个部分:一个按钮和两个数字。

令我惊讶的是,当我单击该按钮时,counter2 按预期增加,但 counter 增加了两次。意思是一直点击按钮会得到如下结果:

1 03 15 2...

为什么全局变量counter是两两递增,而不是一递增?

另外,React State和普通全局变量有什么区别?

当你在 <React.StrictMode> 中包装一个组件时,它会 运行 某些函数两次,其中一次是你的功能组件的函数体:

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

... Function component bodies

- React docs

这只在开发模式下完成,这样做的目的是帮助您捕捉项目中的副作用。

虽然您的组件似乎只被执行一次,但在您的功能组件中放置一个 console.log() 每次状态更改只会 运行 一次。这是因为,从 React 17 开始,他们已将 console.log 方法更新为 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

但是,通过保存对 console.log 方法的引用并使用它来执行您的日志,可以解决此问题。这样做可以让您看到您的组件被执行了两次:

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>
  );
}

上面在组件挂载时会输出如下,说明函数体是运行ning了两次:

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

如果你删除 <React.StrictMode> 组件,那么每次渲染计数器都会增加 1,因为 React 将不再重复调用你的功能组件体,你的组件体只会被调用一次:

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

就全局变量与状态而言,主要区别已在 中指出。也就是说,当您使用 setMethodName() 更新您的状态时,您将导致您的组件主体重新渲染,这在您更新普通变量时不会发生,因为 React 不会意识到对其所做的更改。