Remix loaders forward Cache-Control, but stale-while-revalidate never auto-refreshes client data
0 reputation · 21 Nov 2020, 13:02 UTC
0 reputation · 21 Nov 2020, 13:02 UTC
Remix lets a loader attach a Cache-Control header to its response, so directives such as max-age and stale-while-revalidate reach browsers and CDN caches as documented. The open question sits client-side: when a stale response is served and the browser revalidates in the background, data already rendered through useLoaderData has no documented way to pick up the fresh payload.
As of Remix v2, caching is described only through this low-level header API. Nothing in the framework signals a mounted route that its loader data was revalidated after render. The practical constraint is that a page can keep showing outdated content for the rest of its lifetime unless the application builds its own refresh path — awkward for data that tolerates brief staleness but changes often.
Before committing to a custom strategy, three points need clarifying:
useFetcher or useRevalidator, or to reserve stale-while-revalidate for data that is safe to never refresh client-side?29775 reputation · 21 Nov 2020, 13:17 UTC
The HTTP cache and Remix's client-side data layer operate independently. stale-while-revalidate tells caches serve stale content while you fetch a fresh copy in the background. That background fetch populates the cache for the next navigation or full page load. It does not emit an event, call a callback, or trigger a React re-render in the currently mounted route.
Run these in your Remix v2 app to confirm the behavior before committing to a strategy:
export async function loader() {
return json({ time: new Date().toISOString() }, {
headers: { 'Cache-Control': 'max-age=0, stale-while-revalidate=60' }
});
}
import { useRevalidator } from '@remix-run/react';
export default function Component() {
const { revalidate } = useRevalidator();
const data = useLoaderData();
useEffect(() => {
const id = setInterval(() => revalidate(), 30_000);
return () => clearInterval(id);
}, [revalidate]);
return Server time: {data.time};
}
Reserve stale-while-revalidate for data that is safe to remain static for the page's lifetime (it mainly helps subsequent full loads and CDN hits). For data that changes often and must refresh in place, implement useRevalidator polling or a server-push channel (WebSockets, SSE) rather than relying on HTTP cache directives.
Which Remix/React Router version is installed? Run npm ls @remix-run/react react-router or check package.json. If you are already on React Router v7 (or a v6.4+ data-router build), the answer may differ — newer versions expose useRevalidator with unstable_ cache APIs that could change the recommendation.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.