使用 create-react-app 创建的 React 应用程序无故递增模块范围的变量

React application created using create-react-app increments module-scoped variable without reason

我有一个使用 create-react-app 创建的 React 应用程序。我正在测试一些东西并创建了以下代码:

import React, {useState} from "react";

var a = 1;

function useForceUpdate() {
  const [state, setState] = useState(true);

  return [() => setState(!state)];
}

function App() {
  const [forceUpdate] = useForceUpdate();
  a++;
  console.log(a);

  return (
    <div onClick={forceUpdate}>
      {a}
    </div>
  );
}

export default App;

出于某种原因,它以 3 的值开始,每次单击它都会递增 2 或 3,而不是 1,但这只发生在我现有的项目中,该项目具有其他库,例如酶、react-hooks -测试库和其他。在一个只更改了 App.js 代码的新项目中,它从 3 开始,并始终在单击时恰好递增 2。我在 codepen 上试过它,它以 2 的值开始,并按应有的方式递增 1。这是代码笔(将此处的.js文件:https://reactjs.org/redirect-to-codepen/hello-world替换为以下代码):

var a = 1;

function useForceUpdate() {
  const [state, setState] = React.useState(true);

  return [() => setState(!state)];
}

function App() {
  const [forceUpdate] = useForceUpdate();
  a++;
  console.log(a);

  return (
    <div onClick={forceUpdate}>
      {a}
    </div>
  );
}

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

在 codesandbox 上(只需将其中的 .js 文件替换为下面提供的文件:https://codesandbox.io/s/new?file=/src/App.js)它再次以值 3 开始,每次递增 2:

import React from "react";

var a = 1;

function useForceUpdate() {
  const [state, setState] = React.useState(true);

  return [() => setState(!state)]
}

function App() {
  const [forceUpdate] = useForceUpdate();
  a++;
  console.log(a);

  return (
    <div onClick={forceUpdate}>
      {a}
    </div>
  );
}

export default App;

为什么他们的行为如此不同?

发生这种情况是因为 React's Strict Mode。React 的严格模式会双重调用某些函数,以识别您的应用程序中任何不需要的副作用。您可以在这里阅读更多相关信息:React Strict Mode

现在,如果您转到应用程序的 index.js 文件,您会看到该应用程序已被严格模式包装。 codesandbox 中 index.js 文件的情况类似。

例如,

const rootElement = document.getElementById("root");
ReactDOM.render(
  <StrictMode>
    <App />
  </StrictMode>,
  rootElement
);

但是在 codepen 的情况下,代码没有任何 StrictMode 包装因此,它只添加一次到 a.

这是关于将文件分成模块,但我无法解释幕后到底发生了什么。最有可能的是,以某种方式连接模块只是读取文件,而不是将其代码包含在主代码中。这将增加变量。

您可以轻松查看:

  • 第一种情况 - 在单独的文件(模块)中创建组件并将其导入根目录 index.js
  • 第二种情况 - 在一个文件(模块)中通过调用 ReactDOM.render 创建组件

并在组件外添加console.log

  • 在第一种情况下 - 您将看到 3 个日志,2 个位于组件外部,1 个位于组件内部。
  • 第二种情况 - 2 根原木,1 根在外面,1 根在里面

当然在第一种情况下它以 3 开头,因为您使用的是捆绑代码。

但在我看来,在组件代码或状态管理器之外定义组件更改变量是错误的