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

问题描述

我有一个使用 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-testing - 图书馆和其他。在仅更改 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')
);

代码和框上(只需将其中的 .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 文件,您将看到该应用程序由严格模式包装。代码沙盒中的 index.js 文件也类似。

例如

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

然而,在 codepen 的情况下,代码没有任何 StrictMode 包装,因此,它只向 a 添加一次。

,

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

您可以轻松查看:

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

并在组件外添加 console.log

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

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

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