I’ve searched around and all the similar posts either dont apply or have no effect. I have a very simplified React app (v18.2.0) and im wanting to do some API calls and other logic in my app on render using useEffect. My understanding is this should only trigger once when providing an empty array as a param.
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 config:
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(),
],
};
Looked into this post, Ive verified im not using Strict Mode, there doesnt seem to be anything that is triggering a re-render, and the component isnt being used more than once.
2
Answers
UseEffect hooks are always executed at least two times. Even when you use an empty dependency array
The first time it executes before the component is mounted on the DOM, and the second time is after it gets mounted into the DOM.
If you want overcome this, and only run your
useEffect
one time, apply a custom hook to detect if the component is mounted or not.Usually, people apply this as a reusable custom hook using a ref. Or they apply the logic right into their code by using
useState()
It’s pretty simple to create:
Using state:
Or if you want, Using refs:
You can then use it in any component you want to detect if the component is mounted or not:
If you want, there’s already an npm package for this hook, you can download it from here:
Then in the same way:
Using the reusable custom hook approach with ref is the ultimate solution for any scenario in my experience.
useEffect
hook is called once after the component is mounted. Currently, a possible cause can be a<StrictMode>
. Check yourapp.jsx
to check whether it’s enabled or not.Strict mode runs in development mode and can be enabled by adding a component at the beginning of the application. It checks for potential problems in the code, such as possible memory leaks, and warns the user about their presence.