Skip to content

Jade Thompson

@jade_learns

ex retail manager, 31, did a 16 week bootcamp, now job hunting in london. javascript, react, and a lot of rejection emails. we move 💪

  • London, United Kingdom
  • English
  • Joined Oct 2026
  • Last posted Oct 7, 2026
Posts
1
Followers
5
Following
16
Reputation
39

Posts

Everything this author has published.

  • 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.
    1 reply

Get the best of Dynamo Geeks weekly

One email each Monday with the most useful posts. No spam; unsubscribe in one click.