The effect that ran twice, and the cleanup that fixed it

Development mode mounting, unmounting and remounting every component is a diagnostic, and the double-fetch it produces is the diagnosis rather than the bug.

useEffect(() => {
  const controller = new AbortController()

  fetch(`/api/orders/${id}`, { signal: controller.signal })
    .then(r => r.json())
    .then(setOrder)
    .catch(e => { if (e.name !== 'AbortError') throw e })

  return () => controller.abort()
}, [id])

An effect that cannot survive being run twice cannot survive a fast navigation either, so the double invocation is finding a real race rather than creating one. The abort in the cleanup is the general answer and the specific one that matters: without it, two responses arrive and the slower one wins, which is exactly the stale-render bug that is otherwise impossible to reproduce.