useEffect Runs Twice in React Strict Mode – Why & How to Fix It | FreeLearning365.com

useEffect Runs Twice in React Strict Mode – Why & How to Fix It | FreeLearning365.com
🔥 React Strict Mode Guide

useEffect Runs Twice in
React Strict Mode — Why & How to Fix It

⚡ useEffect executes twice in development with React Strict Mode

React 19 • Next.js 15 • TypeScript • Vite • React Router • Redux Toolkit

📘 FreeLearning365.com 🕒 Updated July 20, 2026 12 min read

🌀 Why Does useEffect Run Twice in Development?

If you've been working with React 18+ in development mode, you've probably noticed that useEffect hooks run twice on mount. This isn't a bug — it's a deliberate feature of React Strict Mode designed to help you identify and fix side-effect bugs before they reach production.

The behavior looks like this:

                    // Console output in development with Strict Mode:
                    useEffect ran!  // First mount
                    useEffect cleanup!  // Cleanup before re-mount
                    useEffect ran!  // Second mount (re-run)
                

Why does React do this? React Strict Mode intentionally mounts, unmounts, and re-mounts components in development to:

  • Detect side-effect bugs — If your effect doesn't clean up properly, you'll notice it when the effect runs twice.
  • Prepare for concurrent features — React 18+ can mount, unmount, and re-mount components during rendering (suspense, transitions).
  • Enforce pure components — Your components should work correctly even if they mount and unmount multiple times.
  • Catch memory leaks — If you don't clean up event listeners, subscriptions, or timers, you'll see the problem quickly.
✅ Good news: This behavior only happens in development mode with Strict Mode enabled. In production, useEffect runs only once (or when dependencies change).
⚠️ Important: Don't disable Strict Mode to "fix" this behavior. It's a valuable tool for writing bug-free React code. Instead, learn to write effects that work correctly even when run twice.

⚡ Quick Reference — Key Facts at a Glance

✅ Development only
useEffect runs twice only in development with Strict Mode.
🟠 Production runs once
In production, useEffect runs once (or when deps change).
🔴 Cleanup is required
Always return a cleanup function from useEffect.
🟣 Detects bugs early
Double execution helps catch side-effect bugs.
🔵 Use useRef for one-time
Use a ref to track if the effect has already run.

📋 Golden Rules for useEffect in Strict Mode

  • 🧹 Always return a cleanup function — Every useEffect that creates side effects should clean them up.
  • 🔄 Don't rely on mount/unmount order — Your effect should work correctly even if it runs multiple times.
  • 📦 Use useRef for one-time initialization — Track if the effect has already run with a ref.
  • 🔗 Include all dependencies — Missing dependencies can cause bugs that double execution reveals.
  • Embrace Strict Mode — It helps you write more robust, production-ready code.
  • 📝 Use useEffect for side effects only — Not for data fetching that should only happen once (use libraries like SWR, React Query, or use hook).

🧩 Detailed Breakdown — Every Scenario Solved

Each card below dives deep into a specific aspect of useEffect double execution, with root causes, code examples, and step-by-step fixes.

🛡️ Prevention — Write Robust useEffect Hooks

🔹 1. Always Clean Up Side Effects
Every useEffect that creates subscriptions, timers, or event listeners should return a cleanup function.
🔹 2. Use useRef for One-Time Initialization
Track if your effect has already run using useRef(false) to prevent double execution in development.
🔹 3. Use useEffect for Side Effects Only
For data fetching, consider using libraries like SWR, React Query, or the new use hook in React 19.
🔹 4. Include All Dependencies
The React exhaustive-deps ESLint rule helps you catch missing dependencies.
🔹 5. Test in Production Mode
Remember that double execution only happens in development. Build and test your app in production mode to verify behavior.
💡 Pro Tip: In React 19, the new use hook for promises works differently from useEffect and may not have the same double-execution behavior in Strict Mode. Consider using use for data fetching.

❓ Frequently Asked Questions

Does useEffect run twice in production?

No. useEffect only runs twice in development mode when React Strict Mode is enabled. In production builds, it runs once (or whenever dependencies change).

This is because Strict Mode is a development-only tool that helps catch side-effect bugs. It's automatically disabled in production builds.

Should I disable Strict Mode to stop double execution?

No. Disabling Strict Mode to "fix" double execution is a bad practice. Strict Mode helps you catch bugs early and write more robust code.

Instead of disabling it, learn to write useEffect hooks that work correctly even when run twice. The double execution is a feature, not a bug.

🚨 Warning: Disabling Strict Mode can hide bugs that will only surface in production when components mount/unmount in unexpected ways.
Does React 19 change the double execution behavior?

No. React 19 maintains the same Strict Mode behavior as React 18. useEffect still runs twice in development with Strict Mode enabled.

However, React 19 introduces the use hook for promises and contexts, which may be a better choice for data fetching in some cases. The use hook has different behavior and may not double-execute in the same way.

✅ React 19 compatibility: All fixes in this guide work perfectly with React 19 and Next.js 15.
How do I debug double execution issues?

Best practices for debugging:

  1. Add console logs — Log when the effect runs and cleans up.
  2. Check your cleanup function — Make sure it properly cleans up all side effects.
  3. Use useRef — Track if the effect has already run.
  4. Check dependencies — Missing dependencies can cause unexpected behavior.
  5. Build in production mode — Verify that the double execution doesn't happen in production.
  6. Use React DevTools — Inspect component mounts and unmounts.
What about useLayoutEffect? Does it run twice too?

Yes. useLayoutEffect also runs twice in Strict Mode development, just like useEffect.

The same rules apply: always return a cleanup function and ensure your layout effects work correctly even when run multiple times.

// ✅ Both useEffect and useLayoutEffect need cleanup
                        useLayoutEffect(() => {
                          const observer = new ResizeObserver(() => {});
                          observer.observe(element);

                          return () => {
                            observer.disconnect(); // ✅ Cleanup
                          };
                        }, []);
Does this affect Next.js 15 server components?

No. Server components in Next.js 15 don't use hooks like useEffect. They're rendered on the server and don't have the same lifecycle.

However, if you're using client components with 'use client', the double execution behavior applies in development with Strict Mode. Client components still follow the same React rules.

// ✅ Client component with useEffect
                        'use client';

                        function MyComponent() {
                          useEffect(() => {
                            // This runs twice in development with Strict Mode
                            console.log('Effect ran!');

                            return () => {
                              console.log('Cleanup!');
                            };
                          }, []);

                          return <div>Hello</div>;
                        }
💡 Pro Tip: In Next.js 15, you can use the use hook for data fetching in server components, which behaves differently from useEffect.

📘 FreeLearning365.com  —  Master React, Next.js, TypeScript & the modern web stack.

Built with ❤️ for developers everywhere.

Post a Comment

0 Comments