When caching async data per key, make invalidation race-safe and avoid unnecessary reloads.
1) Invalidate with per-key generations (or version tokens)
2) Coalesce refreshes to prevent duplicate reads
3) Invalidate only when dependencies can actually change
Example pattern (generation-guarded reads):
const generationRef = useRef(new Map<string, number>());
function bump(keys: Iterable<string>) {
for (const key of keys) {
generationRef.current.set(key, (generationRef.current.get(key) ?? 0) + 1);
}
}
async function readForKey(key: string) {
const gen = generationRef.current.get(key) ?? 0;
const value = await fetchSomethingForKey(key);
// Discard stale responses
if ((generationRef.current.get(key) ?? 0) !== gen) return;
setCache(key, value);
}
function refreshCache(keys: Iterable<string>) {
bump(keys);
for (const key of keys) void readForKey(key);
}
Apply this approach to file contents, diff snapshots, and any other cached async data where late responses or StrictMode remounts can cause out-of-order updates.