react 中出现了代码执行多次(例如,console.log 输出了两次)

在 React 中,当你看到某些代码执行了多次(例如,console.log 输出了两次),这通常是由几个常见原因导致的:

  1. 严格模式(Strict Mode)

    在开发模式下,React 的严格模式会故意使组件重新渲染两次,以便更容易发现潜在的副作用和其他问题。你可以检查你的 index.js 或者 main.js 文件,看看是否有 <React.StrictMode> 包裹了你的应用。

  2. 双重渲染

    React 可能会因为某些状态变化或者父组件的重新渲染导致子组件重新渲染多次。

  3. 热模块替换(Hot Module Replacement, HMR)

    在开发过程中,HMR 可能会导致组件重新加载,尤其是在使用一些开发工具和环境时。

解决方法

为了检查和解决这个问题,你可以尝试以下步骤:

1. 检查是否启用了严格模式

index.jsmain.js 中,如果你看到如下代码,可以注释掉 <React.StrictMode> 并观察行为变化:

js 复制代码
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

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

2. 添加唯一的 key 属性:(切记,很重要!)

如果你在列表中渲染元素,确保每个元素都有唯一的 key 属性。这有助于 React 更好地管理列表项。

js 复制代码
import React, { useState, useEffect } from 'react';

const App = () => {
  const [listData, setListData] = useState([]);

  useEffect(() => {
    // 初始化加载数据
    const initialData = Array.from({ length: 5 }, (_, i) => `Item ${i + 1}`);
    setListData(initialData);
  }, []);

  return (
      <div className="content">
        {listData.map((item, index) => (
          <div key={index} className="list-item">
            {item}
          </div>
        ))}
      </div>
  );
};

export default App;

3. 使用 useEffect 的依赖项:(最容易导致。。。。。。)

检查 useEffect 是否有明确的依赖项。比如:

jsx 复制代码
useEffect(() => {
 console.log('handleLoadMore');
 handleLoadMore();
}, [依赖项数组]);
  • 第一个参数是一个回调函数,其中包含副作用代码。
  • 第二个参数是依赖项数组,控制副作用的执行时机。

当依赖项数组为空时,useEffect 仅在组件首次渲染后执行一次。之后即使组件重新渲染(比如因为状态或属性变化),该副作用也不会再次执行。

js 复制代码
useEffect(() => {
  // 依赖项变化时执行副作用
}, [dep1, dep2]);

当依赖项数组包含特定变量时,useEffect 会在组件首次渲染后执行,并在任何一个依赖项发生变化时重新执行。

js 复制代码
useEffect(() => {
  // 每次渲染后执行副作用
});

如果没有提供依赖项数组,useEffect 会在每次组件渲染后执行(记得设置一个空数组[])。这通常会导致性能问题,除非你的副作用非常轻量且必须每次渲染后都执行。

js 复制代码
useEffect(() => {
  const handle = setInterval(() => {
    console.log('Interval running');
  }, 1000);

  return () => {
    clearInterval(handle);
  };
}, []);

有时候需要在组件卸载或副作用重新运行之前进行清理。例如,取消订阅或清除计时器。

4. 排除 HMR 的影响

确保热模块替换没有干扰到你的调试。你可以在开发模式下尝试禁用 HMR。

(1)Create React App:

在你的 .env 文件中添加:

sh 复制代码
FAST_REFRESH=false

如果没有 .env 文件,可以在启动命令前添加环境变量:

sh 复制代码
FAST_REFRESH=false npm start

(2)Webpack:

Create React App 默认隐藏了 Webpack 配置,所以你需要使用 react-app-rewiredcraco 来覆盖配置。以下是使用 craco 的示例:

sh 复制代码
npm install @craco/craco

创建一个 craco.config.js 文件,禁用 HMR:

js 复制代码
module.exports = {
  webpack: {
    configure: (webpackConfig, { env, paths }) => {
      if (env === 'development') {
        webpackConfig.devServer = {
          ...webpackConfig.devServer,
          hot: false,
        };
      }
      return webpackConfig;
    },
  },
};

修改 package.json 的启动脚本:

js 复制代码
"scripts": {
  "start": "craco start",
  "build": "craco build",
  "test": "craco test",
  "eject": "react-scripts eject"
}

(3)自定义的 Webpack:

如果你有自定义的 Webpack 配置,可以直接在 webpack.config.js 中禁用 HMR:

js 复制代码
module.exports = {
  // ...其他配置
  devServer: {
    hot: false,
  },
};

(4)Vite:

如果你使用 Vite 作为构建工具,可以通过修改 Vite 配置来禁用 HMR:

js 复制代码
export default {
  server: {
    hmr: false,
  },
};

(5)Next.js:

Next.js 使用其自己的 Webpack 配置,禁用 HMR 可能需要一些额外步骤:

自定义 next.config.js:

js 复制代码
module.exports = {
  webpackDevMiddleware: config => {
    config.watchOptions = {
      poll: 300,
      aggregateTimeout: 300,
      ignored: /node_modules/,
    };
    return config;
  },
};

5. 调试工具

使用 Facebook 的 React DevTools 调试工具,观察组件的渲染情况和状态变化,找到导致重复渲染的具体原因。

相关推荐
Devil枫20 分钟前
Vue 3 单元测试与E2E测试
前端·vue.js·单元测试
尚梦1 小时前
uni-app 封装刘海状态栏(适用小程序, h5, 头条小程序)
前端·小程序·uni-app
GIS程序媛—椰子1 小时前
【Vue 全家桶】6、vue-router 路由(更新中)
前端·vue.js
前端青山2 小时前
Node.js-增强 API 安全性和性能优化
开发语言·前端·javascript·性能优化·前端框架·node.js
毕业设计制作和分享2 小时前
ssm《数据库系统原理》课程平台的设计与实现+vue
前端·数据库·vue.js·oracle·mybatis
从兄3 小时前
vue 使用docx-preview 预览替换文档内的特定变量
javascript·vue.js·ecmascript
清灵xmf4 小时前
在 Vue 中实现与优化轮询技术
前端·javascript·vue·轮询
大佩梨4 小时前
VUE+Vite之环境文件配置及使用环境变量
前端
GDAL4 小时前
npm入门教程1:npm简介
前端·npm·node.js
小白白一枚1115 小时前
css实现div被图片撑开
前端·css