Loaders and Actions

As covered in Routers, a data router's route objects can carry a "loader" and an "action" function right alongside "path" and "element". Both receive an object with the current "request" (a standard Request) and "params" (the route's URL parameters), and both can be async – whatever they return becomes available to that route's component through a hook, with no extra useEffect() or hand-rolled loading state required.

A route's loader runs before that route's element renders, and is meant for reading data: fetching a record, checking a session, and so on. A route's action runs instead of the loader whenever a non-GET submission is made to that route – typically via a <Form method="post"> or useSubmit() – and is meant for writing data: creating, updating, or deleting something, then usually redirecting or returning validation errors.

This section covers the four hooks that read and react to that loader/action data: useLoaderData() (the loader's return value), useActionData() (the action's return value), useNavigation() (a state object describing an in-progress navigation, handy for a global pending indicator), and useRevalidator() (manually re-running the active loaders without navigating). Together with useBlocker(), already covered under Preventing Transitions, these are hooks that only work underneath a data router – none of them function inside a plain <BrowserRouter><Routes> tree. A few more data-router-only hooks – useFetcher(), useSubmit(), useRouteError(), useAsyncValue(), and useOutletContext() – round out the picture and are covered elsewhere in this section.