Skip to main content

Loaders and Actions

Loaders and actions are the primary way to load and mutate data in React Router. They run on the server in Framework mode and enable powerful patterns like optimistic UI, automatic revalidation, and error handling.

Loaders

Loaders fetch data before a route renders. They’re called before your component renders, ensuring data is ready immediately.

Basic Loader

Loader Function Signature

From lib/router/utils.ts, loaders receive LoaderFunctionArgs:

Accessing Request Data

Loaders receive a standard Web Fetch API Request:

Returning Data

Loaders can return various response types:

Error Handling in Loaders

Errors thrown from loaders are caught by the nearest ErrorBoundary.

Actions

Actions handle data mutations triggered by form submissions or imperative calls.

Basic Action

Action Function Signature

Handling Form Data

Different HTTP Methods

Returning Action Data

Action data is available via useActionData:

Data Flow

The complete data flow for navigation and mutations:

Revalidation

After an action completes, React Router automatically revalidates loaders to keep UI in sync.

Automatic Revalidation

Controlling Revalidation

You can prevent revalidation when it’s not needed:
From lib/router/router.ts, the shouldRevalidate function receives:

Manual Revalidation

Parallel Data Loading

React Router loads all matching route loaders in parallel:

Context and Request Context

In Framework mode, you can provide context to loaders and actions:
Using context in loaders:

Redirects

Redirecting from loaders and actions:
From lib/router/utils.ts, redirect creates a special Response:

Deferred Data

For streaming SSR, you can defer slow data:
Consume deferred data with <Await>:

Type Safety

React Router provides full type inference:

Best Practices

  1. Keep loaders focused - Each loader should fetch data for its route
  2. Use actions for mutations - Keep side effects in actions, not loaders
  3. Return semantic HTTP responses - Use proper status codes (404, 500, etc.)
  4. Leverage parallel loading - Structure routes to load data in parallel
  5. Handle errors gracefully - Throw responses to trigger error boundaries
  6. Use redirect after mutations - Follow the Post/Redirect/Get pattern
  7. Validate in actions - Return validation errors instead of throwing
  8. Revalidate wisely - Use shouldRevalidate to optimize unnecessary loads