smolter
Guides

Revalidation

Refresh only the route data that needs to change.

Compatibility

ReactAvailable in this renderer's browser integration.
React SSRAvailable to this renderer's SSR integration; browser event handlers run after hydration.
PreactAvailable in this renderer's browser integration.
Preact SSRAvailable to this renderer's SSR integration; browser event handlers run after hydration.

Automatic refresh

Successful actions refresh the active page, previously loaded fetchers, and registered root/layout data. A fetcher loader read does not trigger revalidation. Each route can opt out with shouldRevalidate.

Control refresh

shouldRevalidate receives currentUrl, nextUrl, url, reason, defaultShouldRevalidate, and mutation context when available. Returning false skips a refresh. The function must be synchronous.

import type { RevalidationArgs } from "@kasperrt/smolter/react";

export function shouldRevalidate({ reason, actionResult }: RevalidationArgs) {
  if (reason === "action" && actionResult &&
      typeof actionResult === "object" && "changed" in actionResult) {
    return actionResult.changed !== false;
  }

  return true;
}

Manual refresh

useRevalidator returns a function, not an object with state and revalidate fields. Manual refresh also respects shouldRevalidate.

const revalidate = useRevalidator();

<button onClick={() => void revalidate()}>Refresh</button>

Target a route

Pass a route ID or its registered path pattern. An array selects multiple routes. Only active page data, loaded fetchers, and registered layouts matching that target refresh; this does not navigate or load an inactive page. For /items/:id, use that pattern rather than /items/42. Unknown targets do nothing. shouldRevalidate still applies.

const revalidate = useRevalidator();

await revalidate({ route: "/items/:id" });
await revalidate({ route: ["root", "/items/:id"] });

Root and layout data

The Preact root integration registers its root under root by default, or RootModule.id when provided. Set loaderPath to a registered data route when the root needs refreshing. Custom React or Preact layouts can register their own callback on the router and unregister it during cleanup. No endpoint name is assumed.

// Preact application entry
mountApplication(routes, { ...root, loaderPath: "/session" });

// Refresh only root data from a component
const revalidate = useRevalidator();
await revalidate({ route: "root" });

// Custom layout integration
const unregister = router.registerRevalidator("account-layout", refreshAccount);

Avoid stale UI

Opting out means you own the freshness decision. Keep the default true until you can identify no-op actions or URL changes that leave the active loader result valid.