Hooks and effects

Why Effects run twice in development

Treat development remounting as a test that exposes missing cleanup instead of adding a flag to hide the second call.

Strict Mode adds development checks that expose unsafe rendering and missing Effect cleanup.

For an Effect, React may run this sequence in development:

  1. Start synchronization.
  2. Clean it up.
  3. Start it again.

This simulates leaving and returning to the screen. A correct Effect remains safe because cleanup fully stops the first synchronization.

Do not hide the second run with a ref flag:

if (hasRun.current) return
hasRun.current = true

That can hide the warning while leaving the real remount bug. If the user navigates away and back, the component still needs to reconnect correctly.

Fix the pair instead:

useEffect(() => {
  const connection = createConnection(roomId)
  connection.connect()

  return () => connection.disconnect()
}, [roomId])

Operations such as purchases and form submissions belong in event handlers, where a specific action caused them. Server endpoints for important operations should also handle retries and duplicates safely.

Strict Mode behavior is development-only, but the bugs it reveals are real.

Log connect and disconnect calls while changing rooms and mounting the component. Every started connection should have a matching cleanup.

Lesson completed

Take this course offline

Get every free book, course edition, and software download.

Get the download library →