
React useEffect Running Twice? Here’s the Real Reason
Suman Kumar Keshari
Founder of Skilldham and Software Engineer
Intro
You write a useEffect hook in your React component. You refresh the page and suddenly the console log appears twice. At first glance, it looks like a bug in your code. You double-check the dependency array, inspect the component, and still can't figure out why it's happening.
If you've ever experienced React useEffect running twice, you're not alone. Many developers encounter this behavior when working with React 18, especially in development mode. The surprising part is that your code might actually be perfectly correct.
The real reason behind React useEffect running twice often comes down to React StrictMode, a development feature designed to help developers identify side-effects and unsafe lifecycle patterns.
In this guide, we'll explain exactly why React useEffect runs twice, how StrictMode works internally, and how to write side-effects the right way.
Let's fix this.

Why React useEffect Running Twice Happens in React 18
The most common reason behind React useEffect running twice is React StrictMode.
StrictMode is a development tool that helps detect:
unsafe side effects
legacy lifecycle methods
unexpected mutations
improper cleanup functions
When StrictMode is enabled, React intentionally mounts, unmounts, and mounts a component again to ensure your side effects are safe.
Example
import { useEffect } from "react";
export default function Example() {
useEffect(() => {
console.log("Effect executed");
}, []);
return <div>Hello React</div>;
}Output in development
Effect executed
Effect executedAt first glance this looks incorrect, but React is doing this intentionally.
Why React does this
React wants to ensure your effect logic works correctly even if the component:
mounts
unmounts
mounts again
This is important for future React features like concurrent rendering.
If you want to understand React hooks more deeply, read our guide on React Hooks Explained for Beginners on SkillDham.
For official documentation, refer to the React docs: https://react.dev/reference/react/StrictMode
React StrictMode and Double Rendering Explained
To fully understand react useeffect running twice, we need to understand how StrictMode works internally.
When StrictMode is enabled, React runs the following sequence:
Component Mount
↓
useEffect runs
↓
Component Unmount
↓
Component Mount again
↓
useEffect runs againThis process only happens in development mode.
Example with StrictMode
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
ReactDOM.createRoot(document.getElementById("root")).render(
<React.StrictMode>
<App />
</React.StrictMode>
);With StrictMode enabled, React intentionally triggers additional lifecycle checks.
Why this is useful
It helps detect:
missing cleanup functions
memory leaks
unsafe side effects
incorrect dependency arrays
You can read our detailed article on How React Rendering Works for deeper understanding of React internals.
Why React useEffect Running Twice Does NOT Happen in Production
A key thing to remember about react useeffect running twice is that it only happens in development builds.
In production builds:
StrictMode checks are disabled
components render normally
useEffect runs once
Example Production Behavior
useEffect(() => {
console.log("Running once in production");
}, []);Production output:
Running once in productionThis means you usually don't need to worry about fixing it if your logic is correct.
However, if your code triggers duplicate API requests, it may indicate your effect is not written safely.
For best practices on handling side effects, check the official React documentation: https://react.dev/reference/react/useEffect
Common Mistakes Developers Make When Fixing This
When developers see React useEffect running twice, they often try incorrect fixes.
Wrong Solution
let hasRun = false;
useEffect(() => {
if (!hasRun) {
fetchData();
hasRun = true;
}
}, []);This approach introduces global state bugs and breaks React's rendering model.
Another incorrect approach is disabling StrictMode entirely.
Wrong Fix
ReactDOM.createRoot(root).render(<App />);Removing StrictMode hides problems rather than solving them.
Correct mindset
Instead of preventing the second execution, you should make sure your effect is safe to run multiple times.
This concept is called idempotent side effects.
If you're new to React rendering behavior, you may also find our React Re-rendering Explained Guide helpful.
The Correct Pattern for Handling Side Effects
The correct solution to react useeffect running twice is to write effects that handle cleanup properly.
Wrong Example
useEffect(() => {
fetch("/api/data")
.then(res => res.json())
.then(data => setData(data));
}, []);This can cause duplicate API calls.
Correct Example with Cleanup
useEffect(() => {
let isMounted = true;
fetch("/api/data")
.then(res => res.json())
.then(data => {
if (isMounted) {
setData(data);
}
});
return () => {
isMounted = false;
};
}, []);This ensures that your component handles mount and unmount correctly.
Another modern solution is using AbortController.
useEffect(() => {
const controller = new AbortController();
fetch("/api/data", { signal: controller.signal })
.then(res => res.json())
.then(data => setData(data));
return () => controller.abort();
}, []);This prevents memory leaks and duplicate requests.
How to Debug useEffect Issues Properly
If you're confused about React useEffect running twice, debugging properly can help.
Step 1 — Add console logs
useEffect(() => {
console.log("Effect executed");
}, []);Step 2 — Check StrictMode
Look for this wrapper:
<React.StrictMode>Step 3 — Verify dependency arrays
Incorrect dependencies can cause unexpected rerenders.
useEffect(() => {
doSomething();
}, [value]);Step 4 — Ensure cleanup functions exist
Always return cleanup when dealing with:
subscriptions
timers
event listeners
network requests
Debugging side effects is a critical skill when working with modern React applications.
Key Takeaway
React useEffect running twice can be confusing, but it usually happens because of React StrictMode in development mode. Instead of trying to stop React from executing the effect twice, developers should focus on writing safe and predictable side effects.
Key points to remember:
React StrictMode intentionally mounts components twice in development.
This behavior helps detect unsafe side effects.
React useEffect running twice does not happen in production builds.
Proper cleanup functions prevent memory leaks.
Side effects should be written so they can safely run multiple times.
Understanding these patterns will help you write more reliable React applications.
Frequently Asked Questions
Why is React useEffect running twice?
React useEffect runs twice in development because React StrictMode intentionally mounts and unmounts components to detect unsafe side effects. This helps developers identify potential bugs during development.
How do I stop React useEffect from running twice?
You usually should not stop it. Instead, write side effects that are safe to run multiple times and include proper cleanup functions. Removing StrictMode is not recommended.
Does React StrictMode affect production builds?
No. React StrictMode checks only run in development mode. In production builds, components render normally and useEffect executes once.
What is the difference between useEffect and useLayoutEffect?
useEffect runs asynchronously after the browser paints, while useLayoutEffect runs synchronously before the browser updates the screen. useLayoutEffect is mainly used for DOM measurements or layout adjustments.
External Reference
React documentation https://react.dev/reference/react/useEffect