Building a Multi-Page SPA with React RouterEntry 14 of 20

Dynamic Loaders and useRouteLoaderData

Loaders receive { params, request } for dynamic routes. Giving a route an id lets its children read its loader data with useRouteLoaderData(id).

Notes

  • params in the loader is the same object useParams() returns.
  • Detail and edit pages often need the same data. Move the loader to a parent route without an element, and have both children read it.
  • useLoaderData() only returns the closest route's own loader data, so children use useRouteLoaderData('event-detail') to reach the parent's.
  • Throw data(..., { status: 404 }) when the item doesn't exist.

What / Why / When

What

Param-aware loaders and shared parent data.

Why

Fetch once, use in several child routes, no prop drilling.

When

Detail + edit pages, or any nested routes needing the same record.

Code compare

React
// services/events.tsexport async function getEvent(id: string): Promise<EventItem | null> {  const response = await fetch(`${API}/events/${id}`);  if (response.status === 404) return null;  if (!response.ok) throw new Error("Could not fetch event details.");  const data = await response.json();  return data.event;}

With paramsInheritanceStrategy: 'always', children inherit the parent's params and resolved data, which then bind to their inputs.

Angular
// app.config.tsprovideRouter(  routes,  withComponentInputBinding(),  withRouterConfig({ paramsInheritanceStrategy: "always" }),);

Quick reference

TaskReactAngular
Read params in loader/resolver({ params }) => params.eventId(route) => route.paramMap.get('eventId')
Share parent dataid + useRouteLoaderData(id)paramsInheritanceStrategy: 'always' + input
Not foundthrow data(..., { status: 404 })RedirectCommand to not-found