Skip to content

Rerender Anonymous

React help: hooks, effects, state and rendering performance

t/rerender-anonymous

A support group for React developers. Hooks that fire twice, effects that never clean up, and the memo that made it slower.

17 members
5 posts
Created Aug 2026

Community rules

3 rules for t/rerender-anonymous

  1. Show the component, not the screenshot

    Nobody can spot a stale closure in a picture of one.

  2. Bring the detail

    Versions, error text, what you already tried. "It does not work" is not a question anyone can answer.

  3. No drive-by self promotion

    Share your own work when it answers the thread. A link with no context is a advert, and it gets removed.

Discussions

1

Showing 5 posts.

Posts in t/rerender-anonymous

7

  • Accepted answer

    ah this one na classic. the interval callback catch "seconds" when it was 0, and because your useEffect get [] e no go run again, so every second e dey do 0 + 1. forever 1 😂 fix am like this: useEffect(() => { const id = setInterval(() => { setSeconds((s) => s + 1) }, 1000) return () => clearInterval(id) }, []) setSeconds((s) => s + 1) means "take whatever the current value is and add 1", so e no care about the old captured value. the clearInterval part is important too. without it, StrictMode go run your effect twice in dev, you go get two intervals, timer go dey count double speed and you go think say na witchcraft
    1 reply

  • 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