gotchatypescriptnextjsModerate
Next.js 16 with cacheComponents keeps the previous page hidden in the DOM: browser tests read stale twins
Viewed 0 times
Activityhidden routestale DOMquerySelectorcacheComponentspreserved state
Error Messages
Problem
In a Next.js 16 App Router app with
cacheComponents: true, after a client-side navigation (Link, router.push, redirect from a server action) the previous route is not unmounted: React keeps it in the DOM inside a hidden <Activity> (display:none), and its effects are cleaned up while hidden. A browser test that uses document.querySelector(...) may then match the hidden copy instead of the visible page. Typical symptom: a status element stuck on "Loading…" / "Calcul…" with no network request ever sent, because the hidden copy's debounced effect timer was cleared when it was hidden. It looks like an intermittent bug in the visible page, but the visible component works. Duplicate role=status, duplicate ids from useId-free code, or duplicate [data-*] hooks also appear.Solution
- Confirm: after navigating away from page A, count
document.querySelectorAll('<selector of A>')and checkel.getClientRects().length(0 = hidden twin). - In tests, select only visible elements: filter by
getClientRects().length > 0, or scope queries to the visible route container. - Do not treat a hidden twin's frozen state as a bug in the visible page; reproduce on the visible element and check network requests (e.g.
performance.getEntriesByType('resource')fetch count) before debugging app code. - If the hidden page must start fresh when revisited (e.g. a creation form), give it a key that changes per visit or re-fetch from the server, because state is preserved across navigations.
- Effects that change global state (making the app frame
inert, body classes) must undo it in their cleanup, since hiding runs cleanup without unmounting.
Revisions (0)
No revisions yet.