Selective Invalidation and Conditional Refetching
Learn to treat staleness as a targeted concern, using selective invalidation and conditional refetching to restore correctness while keeping rendering stable.
Once a React application introduces caching, performance improves, but the architectural pressure shifts. Data isn’t fetched eagerly anymore; it’s reused. Screens can render instantly from cache, and navigation feels fast. Then the first mutation lands, and a deceptively simple question appears: what should refetch now?
In many codebases, the answer becomes blunt. After any write, everything that might be related is invalidated. Lists refetch. Detail views refetch. Background queries refetch. The UI slips back into loading states, even when only a single field has changed. As the app grows, these cascades become more visible: scrolling lists jump, interactions feel briefly blocked, and network activity spikes after every user action.
That creates a frustrating tradeoff. Refetch aggressively, and correctness improves, but UI stability degrades. Refetch conservatively, and the UI stays calm, but stale data becomes more likely. Without a clear model of what actually became invalid, teams often default to safety through over-invalidation. Over time, confidence in the cache erodes, and manual refetch() calls and ad-hoc effects get layered on top, undoing the very benefits caching was meant to provide.
The deeper issue isn’t that data becomes stale; it’s that staleness gets treated as contagious. A small, localized change is assumed to invalidate entire regions of server state. At that point, the cache stops coordinating correctness and starts behaving like a temporary buffer between refetch storms.
Selective invalidation and conditional refetching fix this. They make it possible to identify which server truths could have changed, which cache entries are actually affected, and when a refetch is worth the cost. Instead of collapsing correctness into a single “refetch everything” move, the cache can converge intentionally, restoring correctness without forcing the UI through unnecessary disruption.
The above diagram compares two flows. In the first, a mutation invalidates a wide set of queries, triggering multiple refetches and visible loading states across the UI. In the second, only the affected cache entries are invalidated. Unaffected queries remain stable, and refetching occurs only when and where the data is actually needed.
Decoupling staleness from refetching
Invalidation is a signal, not an action. When a query is invalidated, it is not refetched immediately. Its cached data is marked as potentially outdated. This distinction matters because it separates recognizing uncertainty from deciding when to revalidate.
Selective invalidation narrows the blast radius of that uncertainty. By targeting only the queries whose underlying server truth may have changed, stable snapshots are preserved for the ...