我四处搜寻,所有类似的帖子要么不适用,要么没有效果。我有一个非常简化的 React 应用程序(v18.2.0),我想在我的应用程序中使用 useEffect 进行渲染时执行一些 API 调用和其他逻辑。我的理解是,当提供空数组作为参数时,这只应该触发一次。
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 配置:
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(),
],
};
查看这篇文章,我已经验证我没有使用严格模式,似乎没有任何东西触发重新渲染,并且该组件没有被多次使用。
UseEffect 挂钩始终至少执行两次。即使您使用空依赖数组
useEffect(()=>{}, [])
第一次在组件挂载到 DOM 之前执行,第二次在组件挂载到 DOM 之后执行。
如果您想克服这个问题,并且只运行一次
useEffect
,请应用自定义挂钩来检测组件是否已安装。
通常,人们通过引用或使用
useState()
来应用此自定义钩子
创建非常简单:
使用状态:
或者如果你愿意,使用参考文献:
然后您可以在任何想要检测该组件是否已安装的组件中使用它:
import useIsMounted from '@lib/useIsMounted'
const App = ()=> {
const isMounted = useIsMounted()
useEffect(()=> {
if(!isMounted) return
// else, here, execute the following code only once, and after mount:
console.log("you'll see me once if you disable strict mode")
}, [])
}
如果你愿意,已经有这个钩子的 npm 包,你可以从这里下载它:
$ npm i use-is-mounted-ref
然后以同样的方式:
import useIsMounted from 'use-is-mounted-ref';
// ... etc