首页 > 解决方案 > 为什么全局变量在 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 0, 3 1, 5 2...

为什么全局变量是counter二加二,而不是一一增加?

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

标签: reactjsreact-state

解决方案


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

这是通过有意双重调用以下函数来完成的:

... 功能组件体

-反应文档

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

看起来你的组件似乎只执行一次,因为console.log()在你的功能组件内部放置一个状态更改只会运行一次。这是因为,从 React 17 开始,他们已经更新了 console.log 方法以登录您的函数的第二次调用:

从 React 17 开始,React 会自动修改 console.log() 等控制台方法,以在对生命周期函数的第二次调用中静默日志

-反应文档

但是,可以通过保存对该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>
  );
}

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

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

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

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

在全局变量与状态方面,主要区别已在上面的评论中指出。也就是说,当您使用 更新您的状态时setMethodName(),您将导致您的组件主体重新呈现,当您更新普通变量时不会发生这种情况,因为 React 不会知道对其所做的更改。


推荐阅读