React 18基础应用中useEffect触发两次问题求助
React 18.2.0 useEffect空依赖仍多次触发的排查与解决
问题背景
搭建了极简React 18.2.0应用,期望通过useEffect配合空依赖数组仅执行一次逻辑,但实际触发多次。已确认:
- 未使用Strict Mode
- 无触发组件重渲染的因素
- 组件仅被渲染一次
相关代码如下:
index.js
import React from "react"; import App from "./src/App"; import { createRoot } from "react-dom/client"; const container = document.getElementById("root"); const root = createRoot(container); root.render(<App />);
App.js
import React, { useEffect } from "react"; const App = () => { useEffect(() => { console.log("trigger app"); }, []); return <div />; }; export default App;
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>My App</title> <script defer src="main.js"></script> </head> <body> <div id="root"></div> </body> </html>
webpack配置
const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const CleanWebpackPlugin = require('clean-webpack-plugin'); module.exports = { mode: "development", entry: "./index.js", output: { path: path.resolve(__dirname, "public"), filename: "main.js", }, target: ["web", "es5"], stats: { children: true }, devServer: { port: "9500", static: ["./public"], open: true, hot: true, liveReload: true, }, devtool: "inline-source-map", resolve: { extensions: [".js", ".jsx", ".json"], }, module: { rules: [ { test: /\.(js|jsx)$/, exclude: /node_modules/, use: "babel-loader", }, { test: /\.css$/, use: ["style-loader", "css-loader"], }, ], }, plugins: [ new HtmlWebpackPlugin({ template: "./public/index.html", }), new CleanWebpackPlugin(), ], };
排查方向与解决方案
1. 修复Webpack Dev Server的热重载冲突
配置中同时开启hot: true和liveReload: true,在React 18开发环境下可能导致页面双重加载,进而触发多次useEffect:
- 修改devServer配置,关闭liveReload:
devServer: { port: "9500", static: ["./public"], open: true, hot: true, liveReload: false, // 禁用liveReload,仅保留HMR },
2. 移除手动注入的脚本
index.html中手动添加了<script defer src="main.js"></script>,同时HtmlWebpackPlugin会自动注入打包后的脚本,导致脚本被加载两次:
- 删除
index.html中的该script标签,由HtmlWebpackPlugin统一管理脚本注入
3. 确认组件挂载次数
添加日志确认组件是否被重复挂载:
const App = () => { console.log("App component mounted"); // 新增挂载日志 useEffect(() => { console.log("trigger app"); }, []); return <div />; };
如果App component mounted打印两次,说明组件确实被重复渲染,需排查webpack入口是否重复、HtmlWebpackPlugin是否存在重复配置等问题
4. 检查Babel配置兼容性
确保@babel/preset-react版本与React 18兼容,推荐使用最新版并配置自动runtime:
{ "presets": [ ["@babel/preset-react", { "runtime": "automatic" }], "@babel/preset-env" ] }
内容的提问来源于stack exchange,提问作者kc drez
相关产品推荐
相关产品推荐

