UNPKG

react-router

Version:

Declarative routing for React

284 lines (221 loc) 6.42 kB
--- 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 ( <div> <h1>Look ma!</h1> <p> I'm still using React Router after like 10 years. </p> </div> ); } ``` ## `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<User>(); 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 <h1>{data.message}</h1>; } ``` 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 `<Form>`, `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 ( <div> <List items={data.items} /> <Form method="post" navigate={false}> <input type="text" name="title" /> <button type="submit">Create Todo</button> </Form> </div> ); } ``` ## `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 `<Form>`, `<Link>`, `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