--- title: Route Object order: 3 --- # Route Object [MODES: data] ## Introduction The objects passed to `createBrowserRouter` are called Route Objects. ```tsx lines=[2-5] createBrowserRouter([ { path: "/", Component: App, }, ]); ``` Route modules are the foundation of React Router's data features, they define: - data loading - actions - revalidation - error boundaries - and more This guide is a quick overview of every route object feature. ## Component The `Component` property in a route object defines the component that will render when the route matches. ```tsx lines=[4] createBrowserRouter([ { path: "/", Component: MyRouteComponent, }, ]); function MyRouteComponent() { return (

Look ma!

I'm still using React Router after like 10 years.

); } ``` ## `middleware` Route [middleware][middleware] runs sequentially before and after navigations. This gives you a singular place to do things like logging and authentication. The `next` function continues down the chain, and on the leaf route the `next` function executes the loaders/actions for the navigation. ```tsx createBrowserRouter([ { path: "/", middleware: [loggingMiddleware], loader: rootLoader, Component: Root, children: [{ path: 'auth', middleware: [authMiddleware], loader: authLoader, Component: Auth, children: [...] }] }, ]); async function loggingMiddleware({ request }, next) { let url = new URL(request.url); console.log(`Starting navigation: ${url.pathname}${url.search}`); const start = performance.now(); await next(); const duration = performance.now() - start; console.log(`Navigation completed in ${duration}ms`); } const userContext = createContext(); async function authMiddleware ({ context }) { const userId = getUserId(); if (!userId) { throw redirect("/login"); } context.set(userContext, await getUserById(userId)); }; ``` See also: - [Middleware][middleware] ## `loader` Route loaders provide data to route components before they are rendered. ```tsx import { useLoaderData, createBrowserRouter, } from "react-router"; createBrowserRouter([ { path: "/", loader: loader, Component: MyRoute, }, ]); async function loader({ params }) { return { message: "Hello, world!" }; } function MyRoute() { let data = useLoaderData(); return

{data.message}

; } ``` See also: - [`loader` params][loader-params] ## `action` Route actions allow server-side data mutations with automatic revalidation of all loader data on the page when called from `
`, `useFetcher`, and `useSubmit`. ```tsx import { createBrowserRouter, useLoaderData, useActionData, Form, } from "react-router"; import { TodoList } from "~/components/TodoList"; createBrowserRouter([ { path: "/items", action: action, loader: loader, Component: Items, }, ]); async function action({ request }) { const data = await request.formData(); const todo = await fakeDb.addItem({ title: data.get("title"), }); return { ok: true }; } // this data will be revalidated after the action completes... async function loader() { const items = await fakeDb.getItems(); return { items }; } // ...so that the list here is updated automatically export default function Items() { let data = useLoaderData(); return (
); } ``` ## `shouldRevalidate` Loader data is automatically revalidated after certain events like navigations and form submissions. This function lets you opt in or out of the default revalidation behavior **for this route's loader**. It does not skip parent or sibling loaders. The default behavior is nuanced to avoid calling loaders unnecessarily. A route loader is revalidated when: - its own route params change - any change to URL search params - after an action is called and returns a non-error status code By defining this function, you opt out of the default behavior completely and can manually control when loader data is revalidated for navigations and form submissions. ```tsx import type { ShouldRevalidateFunctionArgs } from "react-router"; function shouldRevalidate({ formMethod, formAction, defaultShouldRevalidate, }: ShouldRevalidateFunctionArgs) { if ( formMethod === "POST" && formAction?.endsWith("/analytics") ) { return false; } return defaultShouldRevalidate; } createBrowserRouter([ { path: "/", shouldRevalidate, Component: MyRoute, }, ]); ``` To skip revalidation for a single `
`, ``, `useSubmit`, or `fetcher.submit`, pass [`defaultShouldRevalidate={false}`][form-default-should-revalidate] at the call site. Routes without `shouldRevalidate` use that value directly. See [Revalidation Optimization][optimize-revalidation] for call-site opt-out, parent/child behavior, and more examples. [`ShouldRevalidateFunctionArgs` Reference Documentation ↗](https://api.reactrouter.com/v8/interfaces/react-router.ShouldRevalidateFunctionArgs.html) Please note the default behavior is different in [Framework Mode](../modes). ## `lazy` Most properties can be lazily imported to reduce the initial bundle size. ```tsx createBrowserRouter([ { path: "/app", lazy: async () => { // load component and loader in parallel before rendering const [Component, loader] = await Promise.all([ import("./app"), import("./app-loader"), ]); return { Component, loader }; }, }, ]); ``` ## `handle` Route handle allows apps to add anything to a route match in `useMatches` to create abstractions (like breadcrumbs, etc.). ```tsx createBrowserRouter([ { path: "/app", handle: { breadcrumb: "App", }, }, ]); ``` See also: - [`useMatches`][use-matches] --- Next: [Data Loading](./data-loading) [form-default-should-revalidate]: ../../api/components/Form#defaultshouldrevalidate [loader-params]: https://api.reactrouter.com/v8/interfaces/react-router.LoaderFunctionArgs [middleware]: ../../how-to/middleware [optimize-revalidation]: ../../how-to/optimize-revalidation [use-matches]: ../../api/hooks/useMatches