Data Loading
Route loaders fetch data before the component renders. They integrate with the mesh resource system.
Loader
{
path: "/products/:id",
component: () => import("./ProductDetail"),
loader: async ({ params, mesh, signal }) => {
return mesh.resource("product.detail").fetch({ id: params.id }, { signal });
}
}The loader receives:
params— path parametersmesh— the mesh instancesignal— AbortSignal (aborted if navigation is cancelled)
Dependencies
Prefetch data in parallel with the main loader:
{
path: "/orders/:id",
loader: async ({ params, mesh }) => mesh.resource("order.detail").fetch({ id: params.id }),
dependencies: {
customer: (params, mesh) => mesh.resource("customer.detail").fetch({ id: params.customerId }),
products: (params, mesh) => mesh.resource("products.list").fetch()
}
}Dependencies run in parallel with the main loader. If data is already cached, the dependency resolves instantly.
Navigation Rollback
Routes with rollback: true revert the entire navigation if the loader fails:
{
path: "/checkout",
rollback: true,
loader: async ({ mesh }) => {
return mesh.resource("checkout.summary").fetch();
// If this throws, the URL reverts to the previous route
}
}No broken page is ever shown. The user stays on the previous route.
Error Recovery
Auto-retry failed loaders:
{
path: "/dashboard",
loader: async ({ mesh }) => mesh.resource("dashboard.data").fetch(),
errorRecovery: {
retry: 3,
retryDelay: backoff({ base: 1000, max: 10000 }),
fallbackComponent: () => import("./DashboardSkeleton"),
onError: (error) => console.error("Dashboard load failed:", error)
}
}Pending UI
Show a loading state while the loader runs:
{
path: "/products",
component: () => import("./Products"),
pendingComponent: () => import("./ProductsLoading"),
loader: async ({ mesh }) => mesh.resource("products.list").fetch()
}The pendingComponent is shown after defaultPendingMs (default: 200ms) to avoid flash.
Error UI
Show a custom error component when the loader fails:
{
path: "/products/:id",
component: () => import("./ProductDetail"),
errorComponent: () => import("./ProductError"),
loader: async ({ params, mesh }) => mesh.resource("product.detail").fetch({ id: params.id })
}Important Notes
TIP
Loaders run before the component renders. The component receives loader data via useMatch().data.
WARNING
Always pass the loader's signal to your fetch calls. This ensures cancelled navigations don't waste network requests.
Next Steps
- Advanced — Keep-alive, prefetch, shared elements
- SEO & Meta — Document meta management
