Account imageLoginSign UpAccount image
Loading votes....
Save Question

Why does my React useEffect run twice in development even with an empty dependency array?

clock icon

asked 3 months ago

Message icon

1

Eye icon

5

1useEffect(() => {
2 console.log("Effect ran");
3}, []);
1useEffect(() => {
2 console.log("Effect ran");
3}, []);

In production it runs once, but in development I see two logs. This breaks my API calls (they happen twice). Is my code wrong?

1 Answer

This is intentional in React 18+ with Strict Mode enabled. React mounts, unmounts, and remounts components in development to help you find side-effect bugs.

Why does React do this?

To simulate components being unmounted and remounted (e.g., user navigating away and back). It ensures your effects are “resilient” – i.e., they clean up properly and don't assume they only run once.

How to fix

Keep it – it's harmless once you add proper cleanup.

1
2useEffect(() => {
3
4 const controller = new AbortController();
5
6 fetch('/api', { signal: controller.signal })
7
8 .then(res => res.json())
9
10 .then(setData);
11
12
13
14 return () => controller.abort(); // cleanup cancels duplicate
15
16}, []);
17
1
2useEffect(() => {
3
4 const controller = new AbortController();
5
6 fetch('/api', { signal: controller.signal })
7
8 .then(res => res.json())
9
10 .then(setData);
11
12
13
14 return () => controller.abort(); // cleanup cancels duplicate
15
16}, []);
17

Turn off Strict Mode (not recommended) in index.js:

1
2// <React.StrictMode> ← comment this out
3
4 <App />
5
6// </React.StrictMode>
7
1
2// <React.StrictMode> ← comment this out
3
4 <App />
5
6// </React.StrictMode>
7

Use a ref to track first run (workaround, but not idiomatic):

1
2const hasRun = useRef(false);
3
4useEffect(() => {
5
6 if (!hasRun.current) {
7
8 hasRun.current = true;
9
10 // your effect
11
12 }
13
14}, []);
15
1
2const hasRun = useRef(false);
3
4useEffect(() => {
5
6 if (!hasRun.current) {
7
8 hasRun.current = true;
9
10 // your effect
11
12 }
13
14}, []);
15

✅ Takeaway: Design effects to be startable/cleanup-able multiple times. This future-proofs your app for concurrent rendering features.

1

Write your answer here

Top Questions