useEffect fetch running twice in my take-home test?? is my code broken
doing a take-home for a junior role (round 2, we move 💪). simple React app that fetches a list of products. in the network tab i can see the request going out TWICE every time the page loads. i panicked and added a flag so it only fetches once, and now sometimes the list doesn't show at all, which is worse lol. here's the code: import { useEffect, useState } from 'react' let hasFetched = false export default…
Accepted answer
rhys is right. in development, StrictMode mounts your component, unmounts it, and mounts it again, on purpose, to catch effects that don't clean up after themselves. so the effect runs twice in dev only. production runs it once. why your flag breaks things: hasFetched lives outside the component, at module level. it never resets. first mount sets it true, the fake unmount/remount sees true and skips, and if you navigate away and come back later the component mounts fresh with an empty list and never fetches again. empty list. that's your "sometimes nothing". the fix is not to stop the second run, it's to clean up the first one: useEffect(() => { const controller = new AbortController() fetch('/api/products', { signal: controller.signal }) .then((res) => res.json()) .then(setProducts) .catch((err) => { if (err.name !== 'AbortError') setError(err) }) return () => controller.abort() }, []) in dev you'll now see the first request cancelled and the second one complete. delete the flag. and put one line in your README: "effects run twice in dev because of StrictMode, handled with an AbortController cleanup". reviewers love seeing that you know why. in a real app you'd probably use TanStack Query or your framework's loader, but for a take-home this is exactly right.