# How to Manually Trigger Route Revalidation in React Router

> Manually trigger route revalidation in React Router with useRevalidator or router.revalidate(). Force loaders to re-run without navigating and keep your app data fresh.

- Repository: [Remix/react-router](https://github.com/remix-run/react-router)
- Tags: how-to-guide
- Published: 2026-03-06

---

**Use the `useRevalidator` hook inside components or call `router.revalidate()` directly on the router instance to force loaders to re-run without navigating.**

React Router's data routers automatically revalidate loaders after form submissions and navigation events, but sometimes you need to manually trigger route revalidation in React Router when external data changes. Whether you're responding to WebSocket messages, window focus events, or custom refresh buttons, the library provides two primary APIs to force loader re-execution while staying on the current page.

## Understanding Automatic vs. Manual Revalidation

By default, React Router revalidates route loaders after **actions** complete or when the user navigates to a new route. However, real-world applications often need to refresh data in response to events outside this standard lifecycle—such as receiving a push notification, detecting a window refocus, or polling a backend status endpoint. Manual revalidation bridges this gap without requiring a full page reload or artificial navigation.

## Method 1: Using the `useRevalidator` Hook

The `useRevalidator` hook is the idiomatic way to trigger revalidation from within React components. It returns a `Revalidator` object containing a `revalidate` function and a `state` property indicating whether revalidation is in progress.

### Implementation Details

According to the React Router source code, `useRevalidator` is implemented in [`packages/react-router/lib/hooks.tsx`](https://github.com/remix-run/react-router/blob/main/packages/react-router/lib/hooks.tsx) at lines 1503-1516. The hook accesses the `DataRouterContext` and exposes the router's internal `revalidate` method through a stable callback reference.

```tsx
import { useRevalidator } from "react-router";

export function RefreshButton() {
  const { revalidate, state } = useRevalidator();

  return (
    <button
      onClick={() => revalidate()}
      disabled={state === "loading"}
    >
      {state === "loading" ? "Refreshing…" : "Refresh Data"}
    </button>
  );
}

```

## Method 2: Calling `router.revalidate()` Directly

For scenarios outside of React's component tree—such as service workers, external event listeners, or test utilities—you can call `revalidate()` directly on the router instance returned by `createBrowserRouter`, `createMemoryRouter`, or `createHashRouter`.

### Internal Router Mechanics

The core implementation resides in [`packages/react-router/lib/router/router.ts`](https://github.com/remix-run/react-router/blob/main/packages/react-router/lib/router/router.ts) at lines 1640-1662. When invoked, `router.revalidate()` performs several critical operations:

- Creates a deferred promise (`pendingRevalidationDfd`) to track completion
- Aborts any in-flight loads via `interruptActiveLoads()`
- Transitions the router state to `"loading"`
- Initiates an uninterrupted navigation to the current location, re-running all loaders without pushing a new history entry

```tsx
import { createBrowserRouter } from "react-router";

const router = createBrowserRouter([
  {
    path: "/",
    loader: async () => fetch("/api/dashboard").then(r => r.json()),
    element: <Dashboard />,
  },
]);

// Trigger from external context (e.g., after WebSocket message)
router.revalidate().then(() => {
  console.log("All loaders have re-run");
});

```

## When to Use Manual Revalidation

Choose the appropriate API based on your execution context:

| Scenario | Recommended API |
|----------|-----------------|
| Inside React components responding to user interactions | `useRevalidator` hook |
| External event handlers (WebSocket, `window` events) | `router.revalidate()` |
| Service workers or non-React utilities | `router.revalidate()` |
| Testing environments requiring deterministic loader execution | `await router.revalidate()` |

## Advanced Example: Window Focus Revalidation

A common pattern for single-page applications is refreshing data when the user returns to the tab. This combines `useRevalidator` with the `window` focus event:

```tsx
import { useEffect } from "react";
import { useRevalidator } from "react-router";

export function FocusRevalidator() {
  const { revalidate } = useRevalidator();

  useEffect(() => {
    const handleFocus = () => revalidate();
    window.addEventListener("focus", handleFocus);
    return () => window.removeEventListener("focus", handleFocus);
  }, [revalidate]);

  return null;
}

```

## Summary

- **Use `useRevalidator`** when triggering revalidation from React components; it provides reactive state tracking and handles cleanup automatically.
- **Use `router.revalidate()`** for imperative control outside React, such as in service workers, tests, or external event listeners.
- Both methods ultimately invoke the same internal mechanism in [`packages/react-router/lib/router/router.ts`](https://github.com/remix-run/react-router/blob/main/packages/react-router/lib/router/router.ts), which aborts active loads, sets state to `"loading"`, and re-runs all current route loaders without navigation side effects.
- Manual revalidation is essential for keeping UI synchronized with external data sources beyond the standard action-based workflow.

## Frequently Asked Questions

### How do I know when manual revalidation has completed?

The `useRevalidator` hook returns a `state` property that equals `"loading"` during revalidation and `"idle"` when finished. If calling `router.revalidate()` directly, the method returns a `Promise<void>` that resolves once all loaders have re-run, allowing you to use `await router.revalidate()` for deterministic completion detection.

### Can I revalidate a specific route instead of all loaders?

No. React Router's revalidation API is all-or-nothing for the currently active routes. When you trigger `revalidate()`, the router re-runs every loader on the current path. To refresh only specific data, consider using React Query, SWR, or other caching libraries alongside React Router's loaders.

### Does manual revalidation work with client-side route loaders only?

Manual revalidation works with any loader defined in your route configuration, whether it runs on the client or server (in a Remix context). The `router.revalidate()` method simply re-invokes the loader functions defined in your route hierarchy, regardless of where those loaders execute.

### What happens if I call revalidate during an active navigation?

The router handles this gracefully. According to the implementation in [`packages/react-router/lib/router/router.ts`](https://github.com/remix-run/react-router/blob/main/packages/react-router/lib/router/router.ts), calling `revalidate()` during an active navigation first interrupts any in-flight loads, then either piggybacks on the pending navigation's loader phase or initiates a new uninterrupted navigation to the current location. This ensures you never end up with stale data or race conditions.