--- title: Feature Overview order: 1 --- # Feature Overview ## Client Side Routing React Router enables "client side routing". In traditional websites, the browser requests a document from a web server, downloads and evaluates CSS and JavaScript assets, and renders the HTML sent from the server. When the user clicks a link, it starts the process all over again for a new page. Client side routing allows your app to update the URL from a link click without making another request for another document from the server. Instead, your app can immediately render some new UI and make data requests with `fetch` to update the page with new information. This enables faster user experiences because the browser doesn't need to request an entirely new document or re-evaluate CSS and JavaScript assets for the next page. It also enables more dynamic user experiences with things like animation. Client side routing is enabled by creating a `Router` and linking/submitting to pages with `Link` and `
`: ```jsx [10,16,27] import * as React from "react"; import { createRoot } from "react-dom/client"; import { createBrowserRouter, RouterProvider, Route, Link, } from "react-router-dom"; const router = createBrowserRouter([ { path: "/", element: (

Hello World

About Us
), }, { path: "about", element:
About
, }, ]); createRoot(document.getElementById("root")).render( ); ``` ## Nested Routes Nested Routing is the general idea of coupling segments of the URL to component hierarchy and data. React Router's nested routes were inspired by the routing system in Ember.js circa 2014. The Ember team realized that in nearly every case, segments of the URL determine: - The layouts to render on the page - The data dependencies of those layouts React Router embraces this convention with APIs for creating nested layouts coupled to URL segments and data. ```jsx // Configure nested routes with JSX createBrowserRouter( createRoutesFromElements( }> } /> } loader={({ request }) => fetch("/api/dashboard.json", { signal: request.signal, }) } /> }> } loader={redirectIfUser} /> ) ); // Or use plain objects createBrowserRouter([ { path: "/", element: , children: [ { path: "contact", element: , }, { path: "dashboard", element: , loader: ({ request }) => fetch("/api/dashboard.json", { signal: request.signal, }), }, { element: , children: [ { path: "login", element: , loader: redirectIfUser, }, { path: "logout", action: logoutUser, }, ], }, ], }, ]); ``` This [visualization](https://remix.run/_docs/routing) might be helpful. ## Dynamic Segments Segments of the URL can be dynamic placeholders that are parsed and provided to various apis. ```jsx ``` The two segments with `:` are dynamic, and provided to the following APIs: ```jsx // If the current location is /projects/abc/tasks/3 { params.projectId; // abc params.taskId; // 3 }} // and actions action={({ params }) => { params.projectId; // abc params.taskId; // 3 }} element={} />; function Task() { // returned from `useParams` const params = useParams(); params.projectId; // abc params.taskId; // 3 } function Random() { const match = useMatch( "/projects/:projectId/tasks/:taskId" ); match.params.projectId; // abc match.params.taskId; // 3 } ``` See: - [``][path] - [``][loader] - [``][action] - [`useParams`][useparams] - [`useMatch`][usematch] ## Ranked Route Matching When matching URLs to routes, React Router will rank the routes according to the number of segments, static segments, dynamic segments, splats, etc. and pick the _most specific_ match. For example, consider these two routes: ```jsx ``` Now consider the URL is http://example.com/teams/new. Even though both routes technically match the URL (`new` could be the `:teamId`), you intuitively know that we want the second route (`/teams/new`) to be picked. React Router's matching algorithm knows that, too. With ranked routes, you don't have to worry about route ordering. ## Active Links Most web apps have persistent navigation sections at the top of the UI, the sidebar, and often multiple levels. Styling the active navigation items so the user knows where they are (`isActive`) or where they're going (`isPending`) in the app is done easily with ``. ```jsx { return { color: isActive ? "red" : "inherit", }; }} className={({ isActive, isPending }) => { return isActive ? "active" : isPending ? "pending" : ""; }} /> ``` You can also [`useMatch`][usematch] for any other "active" indication outside of links. ```jsx function SomeComp() { const match = useMatch("/messages"); return
  • ; } ``` See: - [`NavLink`][navlink] - [`useMatch`][usematch] ## Relative Links Like HTML ``, `` and `` can take relative paths, with enhanced behavior with nested routes. Given the following route config: ```jsx }> }> } /> ``` Consider the url https://example.com/home/project/123, which renders the following route component hierarchy: ```jsx ``` If `` renders the following links, the hrefs of the links will resolve like so: | In `` @ `/home/project/123` | Resolved `` | | ------------------------------------ | ----------------------- | | `` | `/home/project/123/abc` | | `` | `/home/project/123` | | `` | `/home` | | `` | `/home/project` | Note that the first `..` removes both segments of the `project/:projectId` route. By default, the `..` in relative links traverse the route hierarchy, not the URL segments. Adding `relative="path"` in the next example allows you to traverse the path segments instead. Relative links are always relative to the route path they are _rendered in_, not to the full URL. That means if the user navigates deeper with `` to `` at the URL `/home/project/123/abc`, the hrefs in `` will not change (contrary to plain ``, a common problem with client side routers). ## Data Loading Because URL segments usually map to your app's persistent data, React Router provides conventional data loading hooks to initiate data loading during a navigation. Combined with nested routes, all of the data for multiple layouts at a specific URL can be loaded in parallel. ```jsx { // loaders can be async functions const res = await fetch("/api/user.json", { signal: request.signal, }); const user = await res.json(); return user; }} element={} > { return fetch(`/api/teams/${params.teamId}`); }} element={} > { // of course you can use any data store return fakeSdk.getTeam(params.gameId); }} element={} /> ``` Data is made available to your components through `useLoaderData`. ```jsx function Root() { const user = useLoaderData(); // data from } function Team() { const team = useLoaderData(); // data from } function Game() { const game = useLoaderData(); // data from } ``` When the user visits or clicks links to https://example.com/real-salt-lake/45face3, all three route loaders will be called and loaded in parallel, before the UI for that URL renders. ## Redirects While loading or changing data, it's common to [redirect][redirect] the user to a different route. ```jsx { const user = await fake.getUser(); if (!user) { // if you know you can't render the route, you can // throw a redirect to stop executing code here, // sending the user to a new route throw redirect("/login"); } // otherwise continue const stats = await fake.getDashboardStats(); return { user, stats }; }} /> ``` ```jsx { const data = await request.formData(); const newProject = await createProject(data); // it's common to redirect after actions complete, // sending the user to the new record return redirect(`/projects/${newProject.id}`); }} /> ``` See: - [`redirect`][redirect] - [Throwing in Loaders][throwing] - [`useNavigate`][usenavigate] ## Pending Navigation UI When users navigate around the app, the data for the next page is loaded before the page is rendered. It's important to provide user feedback during this time so the app doesn't feel like it's unresponsive. ```jsx lines=[2,5] function Root() { const navigation = useNavigation(); return (
    {navigation.state === "loading" && }
    ); } ``` See: - [`useNavigation`][usenavigation] ## Skeleton UI with `` Instead of waiting for the data for the next page, you can [`defer`][defer] data so the UI flips over to the next screen with placeholder UI immediately while the data loads. ```jsx lines=[12,22-29,32-35] } loader={async ({ params }) => { // these are promises, but *not* awaited const comments = fake.getIssueComments(params.issueId); const history = fake.getIssueHistory(params.issueId); // the issue, however, *is* awaited const issue = await fake.getIssue(params.issueId); // defer enables suspense for the un-awaited promises return defer({ issue, comments, history }); }} />; function Issue() { const { issue, history, comments } = useLoaderData(); return (
    {/* Suspense provides the placeholder fallback */} }> {/* Await manages the deferred data (promise) */} {/* this calls back when the data is resolved */} {(resolvedHistory) => ( )} }> {/* ... or you can use hooks to access the data */}
    ); } function IssueComments() { const comments = useAsyncValue(); return
    {/* ... */}
    ; } ``` See - [Deferred Data Guide][deferreddata] - [`defer`][defer] - [`Await`][await] - [`useAsyncValue`][useasyncvalue] ## Data Mutations HTML forms are navigation events, just like links. React Router supports HTML form workflows with client side routing. When a form is submitted, the normal browser navigation event is prevented and a [`Request`][request], with a body containing the [`FormData`][formdata] of the submission, is created. This request is sent to the `` that matches the form's ``. Form elements's `name` prop are submitted to the action: ```jsx ``` The normal HTML document request is prevented and sent to the matching route's action (`` that matches the `
    `), including the `request.formData`. ```jsx { const formData = await request.formData(); const newProject = await createProject({ title: formData.get("title"), due: formData.get("due"), }); return redirect(`/projects/${newProject.id}`); }} /> ``` ## Data Revalidation Decades old web conventions indicate that when a form is posted to the server, data is changing and a new page is rendered. That convention is followed in React Router's HTML-based data mutation APIs. After route actions are called, the loaders for all of the data on the page is called again to ensure the UI stays up-to-date with the data automatically. No cache keys to expire, no context providers to reload. See: - [Tutorial "Creating Contacts"][creatingcontacts] ## Busy Indicators When forms are being submitted to route actions, you have access to the navigation state to display busy indicators, disable fieldsets, etc. ```jsx lines=[2,3,6,19-21] function NewProjectForm() { const navigation = useNavigation(); const busy = navigation.state === "submitting"; return (
    ); } ``` See: - [`useNavigation`][usenavigation] ## Optimistic UI Knowing the [`formData`][formdata] being sent to an [action][action] is often enough to skip the busy indicators and render the UI in the next state immediately, even if your asynchronous work is still pending. This is called "optimistic UI". ```jsx function LikeButton({ tweet }) { const fetcher = useFetcher(); // if there is `formData` then it is posting to the action const liked = fetcher.formData ? // check the formData to be optimistic fetcher.formData.get("liked") === "yes" : // if its not posting to the action, use the record's value tweet.liked; return ( ); } ``` See: - [`useFetcher`][fetcher] ## Race Condition Handling React Router will cancel stale operations and only commit fresh data automatically. Any time you have asynchronous UI you have the risk of race conditions: when an async operation starts after but completes before an earlier operation. The result is a user interface that shows the wrong state. Consider a search field that updates a list as the user types: ``` ?q=ry |---------------| ^ commit wrong state ?q=ryan |--------| ^ lose correct state ``` Even though the query for `q?=ryan` went out later, it completed earlier. If not handled correctly, the results will briefly be the correct values for `?q=ryan` but then flip over the incorrect results for `?q=ry`. Throttling and debouncing are not enough (you can still interrupt the requests that get through). You need cancellation. If you're using React Router's data conventions you avoid this problem completely and automatically. ``` ?q=ry |-----------X ^ cancel wrong state when correct state completes earlier ?q=ryan |--------| ^ commit correct state ``` Not only does React Router handle race conditions for a navigation like this, it also handles it for many other cases like loading results for an autocomplete or performing multiple concurrent mutations with [`fetcher`][fetcher] (and its automatic, concurrent revalidations). ## Error Handling The vast majority of your application errors are handled automatically by React Router. It will catch any errors that are thrown while: - rendering - loading data - updating data In practice, this is pretty much every error in your app except those thrown in event handlers (`