| 1 | ---
|
| 2 | title: Routing
|
| 3 | order: 2
|
| 4 | ---
|
| 5 |
|
| 6 | # Routing
|
| 7 |
|
| 8 | [MODES: data]
|
| 9 |
|
| 10 | ## Configuring Routes
|
| 11 |
|
| 12 | Routes are configured as the first argument to `createBrowserRouter`. At a minimum, you need a path and component:
|
| 13 |
|
| 14 | ```tsx
|
| 15 | import { createBrowserRouter } from "react-router";
|
| 16 |
|
| 17 | function Root() {
|
| 18 | return <h1>Hello world</h1>;
|
| 19 | }
|
| 20 |
|
| 21 | const router = createBrowserRouter([
|
| 22 | { path: "/", Component: Root },
|
| 23 | ]);
|
| 24 | ```
|
| 25 |
|
| 26 | Here is a larger sample route config:
|
| 27 |
|
| 28 | ```ts filename=app/routes.ts
|
| 29 | createBrowserRouter([
|
| 30 | {
|
| 31 | path: "/",
|
| 32 | Component: Root,
|
| 33 | children: [
|
| 34 | { index: true, Component: Home },
|
| 35 | { path: "about", Component: About },
|
| 36 | {
|
| 37 | path: "auth",
|
| 38 | Component: AuthLayout,
|
| 39 | children: [
|
| 40 | { path: "login", Component: Login },
|
| 41 | { path: "register", Component: Register },
|
| 42 | ],
|
| 43 | },
|
| 44 | {
|
| 45 | path: "concerts",
|
| 46 | children: [
|
| 47 | { index: true, Component: ConcertsHome },
|
| 48 | { path: ":city", Component: ConcertsCity },
|
| 49 | { path: "trending", Component: ConcertsTrending },
|
| 50 | ],
|
| 51 | },
|
| 52 | ],
|
| 53 | },
|
| 54 | ]);
|
| 55 | ```
|
| 56 |
|
| 57 | ## Route Objects
|
| 58 |
|
| 59 | Route objects define the behavior of a route beyond just the path and component, like data loading and actions. We'll go into more detail in the [Route Object guide](./route-object), but here's a quick example of a loader.
|
| 60 |
|
| 61 | ```tsx filename=app/team.tsx
|
| 62 | import {
|
| 63 | createBrowserRouter,
|
| 64 | useLoaderData,
|
| 65 | } from "react-router";
|
| 66 |
|
| 67 | createBrowserRouter([
|
| 68 | {
|
| 69 | path: "/teams/:teamId",
|
| 70 | loader: async ({ params }) => {
|
| 71 | let team = await fetchTeam(params.teamId);
|
| 72 | return { name: team.name };
|
| 73 | },
|
| 74 | Component: Team,
|
| 75 | },
|
| 76 | ]);
|
| 77 |
|
| 78 | function Team() {
|
| 79 | let data = useLoaderData();
|
| 80 | return <h1>{data.name}</h1>;
|
| 81 | }
|
| 82 | ```
|
| 83 |
|
| 84 | ## Nested Routes
|
| 85 |
|
| 86 | Routes can be nested inside parent routes through `children`.
|
| 87 |
|
| 88 | ```ts filename=app/routes.ts
|
| 89 | createBrowserRouter([
|
| 90 | {
|
| 91 | path: "/dashboard",
|
| 92 | Component: Dashboard,
|
| 93 | children: [
|
| 94 | { index: true, Component: Home },
|
| 95 | { path: "settings", Component: Settings },
|
| 96 | ],
|
| 97 | },
|
| 98 | ]);
|
| 99 | ```
|
| 100 |
|
| 101 | The path of the parent is automatically included in the child, so this config creates both `"/dashboard"` and `"/dashboard/settings"` URLs.
|
| 102 |
|
| 103 | Child routes are rendered through the `<Outlet/>` in the parent route.
|
| 104 |
|
| 105 | ```tsx filename=app/dashboard.tsx
|
| 106 | import { Outlet } from "react-router";
|
| 107 |
|
| 108 | export default function Dashboard() {
|
| 109 | return (
|
| 110 | <div>
|
| 111 | <h1>Dashboard</h1>
|
| 112 | {/* will either be <Home> or <Settings> */}
|
| 113 | <Outlet />
|
| 114 | </div>
|
| 115 | );
|
| 116 | }
|
| 117 | ```
|
| 118 |
|
| 119 | ## Layout Routes
|
| 120 |
|
| 121 | Omitting the `path` in a route creates new [Nested Routes](#nested-routes) for its children without adding any segments to the URL.
|
| 122 |
|
| 123 | ```tsx lines=[3,16]
|
| 124 | createBrowserRouter([
|
| 125 | {
|
| 126 | // no path on this parent route, just the component
|
| 127 | Component: MarketingLayout,
|
| 128 | children: [
|
| 129 | { index: true, Component: Home },
|
| 130 | { path: "contact", Component: Contact },
|
| 131 | ],
|
| 132 | },
|
| 133 |
|
| 134 | {
|
| 135 | path: "projects",
|
| 136 | children: [
|
| 137 | { index: true, Component: ProjectsHome },
|
| 138 | {
|
| 139 | // again, no path, just a component for the layout
|
| 140 | Component: ProjectLayout,
|
| 141 | children: [
|
| 142 | { path: ":pid", Component: Project },
|
| 143 | { path: ":pid/edit", Component: EditProject },
|
| 144 | ],
|
| 145 | },
|
| 146 | ],
|
| 147 | },
|
| 148 | ]);
|
| 149 | ```
|
| 150 |
|
| 151 | Note that:
|
| 152 |
|
| 153 | - `Home` and `Contact` will be rendered into the `MarketingLayout` outlet
|
| 154 | - `Project` and `EditProject` will be rendered into the `ProjectLayout` outlet while `ProjectsHome` will not.
|
| 155 |
|
| 156 | ## Index Routes
|
| 157 |
|
| 158 | Index routes are defined by setting `index: true` on a route object without a path.
|
| 159 |
|
| 160 | ```ts
|
| 161 | { index: true, Component: Home }
|
| 162 | ```
|
| 163 |
|
| 164 | Index routes render into their parent's [Outlet][outlet] at their parent's URL (like a default child route).
|
| 165 |
|
| 166 | ```ts lines=[4,5,10,11]
|
| 167 | import { createBrowserRouter } from "react-router";
|
| 168 |
|
| 169 | createBrowserRouter([
|
| 170 | // renders at "/"
|
| 171 | { index: true, Component: Home },
|
| 172 | {
|
| 173 | Component: Dashboard,
|
| 174 | path: "/dashboard",
|
| 175 | children: [
|
| 176 | // renders at "/dashboard"
|
| 177 | { index: true, Component: DashboardHome },
|
| 178 | { path: "settings", Component: DashboardSettings },
|
| 179 | ],
|
| 180 | },
|
| 181 | ]);
|
| 182 | ```
|
| 183 |
|
| 184 | Note that index routes can't have children.
|
| 185 |
|
| 186 | ## Prefix Route
|
| 187 |
|
| 188 | A route with just a path and no component creates a group of routes with a path prefix.
|
| 189 |
|
| 190 | ```tsx lines=[3]
|
| 191 | createBrowserRouter([
|
| 192 | {
|
| 193 | // no component, just a path
|
| 194 | path: "/projects",
|
| 195 | children: [
|
| 196 | { index: true, Component: ProjectsHome },
|
| 197 | { path: ":pid", Component: Project },
|
| 198 | { path: ":pid/edit", Component: EditProject },
|
| 199 | ],
|
| 200 | },
|
| 201 | ]);
|
| 202 | ```
|
| 203 |
|
| 204 | This creates the routes `/projects`, `/projects/:pid`, and `/projects/:pid/edit` without introducing a layout component.
|
| 205 |
|
| 206 | ## Dynamic Segments
|
| 207 |
|
| 208 | If a path segment starts with `:` then it becomes a "dynamic segment". When the route matches the URL, the dynamic segment will be parsed from the URL and provided as `params` to other router APIs.
|
| 209 |
|
| 210 | ```ts lines=[2]
|
| 211 | {
|
| 212 | path: "teams/:teamId",
|
| 213 | loader: async ({ params }) => {
|
| 214 | // params are available in loaders/actions
|
| 215 | let team = await fetchTeam(params.teamId);
|
| 216 | return { name: team.name };
|
| 217 | },
|
| 218 | Component: Team,
|
| 219 | }
|
| 220 | ```
|
| 221 |
|
| 222 | ```tsx
|
| 223 | import { useParams } from "react-router";
|
| 224 |
|
| 225 | function Team() {
|
| 226 | // params are available in components through useParams
|
| 227 | let params = useParams();
|
| 228 | // ...
|
| 229 | }
|
| 230 | ```
|
| 231 |
|
| 232 | You can have multiple dynamic segments in one route path:
|
| 233 |
|
| 234 | ```ts
|
| 235 | {
|
| 236 | path: "c/:categoryId/p/:productId";
|
| 237 | }
|
| 238 | ```
|
| 239 |
|
| 240 | ## Optional Segments
|
| 241 |
|
| 242 | You can make a route segment optional by adding a `?` to the end of the segment.
|
| 243 |
|
| 244 | ```ts
|
| 245 | {
|
| 246 | path: ":lang?/categories";
|
| 247 | }
|
| 248 | ```
|
| 249 |
|
| 250 | You can have optional static segments, too:
|
| 251 |
|
| 252 | ```ts
|
| 253 | {
|
| 254 | path: "users/:userId/edit?";
|
| 255 | }
|
| 256 | ```
|
| 257 |
|
| 258 | ## Splats
|
| 259 |
|
| 260 | Also known as "catchall" and "star" segments. If a route path pattern ends with `/*` then it will match any characters following the `/`, including other `/` characters.
|
| 261 |
|
| 262 | ```ts
|
| 263 | {
|
| 264 | path: "files/*";
|
| 265 | loader: async ({ params }) => {
|
| 266 | params["*"]; // will contain the remaining URL after files/
|
| 267 | };
|
| 268 | }
|
| 269 | ```
|
| 270 |
|
| 271 | You can destructure the `*`, you just have to assign it a new name. A common name is `splat`:
|
| 272 |
|
| 273 | ```tsx
|
| 274 | const { "*": splat } = params;
|
| 275 | ```
|
| 276 |
|
| 277 | ---
|
| 278 |
|
| 279 | Next: [Route Object](./route-object)
|
| 280 |
|
| 281 | [outlet]: https://api.reactrouter.com/v7/functions/react-router.Outlet.html
|