Receber por email
← Voltar para o catálogo

web-routing-react-router

Client-side routing with data APIs — loaders, actions, error boundaries, search params, nested layouts, and code splitting

11estrelas
Atualizado há 7 meses

Ver no GitHub ↗ Licença: MIT

Como adicionar

/plugin marketplace add agents-inc/skills

O comando exato pode variar conforme o repositório. Confira o README no GitHub.

Para o autor da skill

Cole no README do seu repo

Mostra que sua skill está catalogada na Skillteca, gera backlink e tráfego rastreável.

[![Skillteca](https://www.skillteca.com.br/api/badge/web-routing-react-router/svg)](https://www.skillteca.com.br/skills/web-routing-react-router)

Alerta por categoria

Receba novas skills de Design e Frontend toda segunda

1 email curto, só com as skills novas de Design e Frontend. 4 minutos de leitura, sem spam, cancela com 1 clique.

Você confirma o email no primeiro envio. Sem spam. Cancela com 1 clique.

Ler descrição completa

React Router Patterns

Quick Guide: React Router v7 has three modes: Declarative (<BrowserRouter>), Data (createBrowserRouter), and Framework (Vite plugin). This skill covers Data Mode — the sweet spot for SPAs needing loaders, actions, and pending states without a full framework. All imports come from "react-router" (the react-router-dom package is removed). defer() and json() are removed in v7 — return plain objects from loaders. Form method values are now uppercase ("POST", not "post").

<critical_requirements>

CRITICAL: Before Using This Skill

All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering, import type, named constants)

(You MUST use createBrowserRouter + <RouterProvider> for Data Mode — NEVER use <BrowserRouter> with <Routes> if you need loaders, actions, or fetchers)

(You MUST import from "react-router" — the react-router-dom package is removed in v7. All exports, including RouterProvider and createBrowserRouter, come from "react-router")

(You MUST return plain objects from loaders — json() and defer() are removed in v7. Return { data } directly or use Response.json())

(You MUST use throw redirect() in loaders and shared helpers to short-circuit execution — return redirect() also works but does not stop execution in helper function call stacks)

(You MUST use errorElement or ErrorBoundary on routes — unhandled loader/action errors crash the entire router)

</critical_requirements>

Auto-detection: React Router, createBrowserRouter, RouterProvider, useLoaderData, useActionData, useNavigation, useSearchParams, useFetcher, useRouteError, useParams, useNavigate, Outlet, NavLink, Form, loader, action, errorElement, ErrorBoundary, redirect, isRouteErrorResponse, route.lazy, useOutletContext, shouldRevalidate, useRevalidator

When to use:

  • Building React SPAs that need data loading, form actions, or pending states
  • Apps requiring nested layouts with shared UI (sidebars, headers)
  • Route-level error boundaries and not-found handling
  • URL search param state management
  • Code splitting at the route level
  • Non-navigating mutations (fetchers for inline forms, buttons)

Key patterns covered:

  • Data Mode setup with createBrowserRouter and RouterProvider
  • Route loaders and actions for data fetching and mutations
  • Nested layouts with <Outlet /> and useOutletContext
  • Type-safe navigation with Link, NavLink, useNavigate, redirect
  • Error handling with errorElement, useRouteError, isRouteErrorResponse
  • Search params with useSearchParams
  • Non-navigating mutations with useFetcher
  • Code splitting with route.lazy
  • Navigation state with useNavigation
  • Protected routes and auth guard patterns

When NOT to use:

  • Simple apps with 1-2 pages and no data loading (Declarative Mode with <BrowserRouter> is sufficient)
  • Full-stack SSR apps (use Framework Mode or an SSR framework instead)
  • Static sites without client-side navigation

Examples

  • [Core Setup & Route Config](examples/core.md) -- createBrowserRouter, RouterProvider, route objects, basic loaders
  • [Data Loading & Actions](examples/data-loading.md) -- loaders, actions, Form, useFetcher, revalidation
  • [Navigation & Search Params](examples/navigation.md) -- Link, NavLink, useNavigate, redirect, useSearchParams
  • [Error Handling & Code Splitting](examples/error-handling.md) -- errorElement, useRouteError, route.lazy, pending UI
  • [Layouts & Auth Guards](examples/layouts.md) -- Outlet, useOutletContext, protected routes, nested layouts

For quick API reference (hooks, components, route options), see [reference.md](reference.md).

<philosophy>

Philosophy

React Router v7 treats the router as a data layer, not just a URL matcher. Routes define what data to load (loader), what mutations to handle (action), and what errors to catch (errorElement) — all before the component renders. This moves data orchestration out of components and into the route tree, eliminating loading waterfalls and duplicated error handling.

Core principles:

  • Routes own their data — Loaders fetch before render, actions handle mutations. Components receive data, they do not fetch it.
  • URL is the source of truth — Search params, path params, and navigation state all live in the URL. No hidden state.
  • Errors bubble up — Like React error boundaries, errorElement catches errors at the nearest route. Unhandled errors bubble to the parent.
  • Revalidation is automatic — After a successful action, all active loaders re-run. No manual cache invalidation needed. (In v7, loaders skip revalidation after action errors unless shouldRevalidate opts in.)
  • Fetchers are for mutations without navigation — useFetcher handles inline forms, buttons, and background saves without changing the URL.

When to use Data Mode:

  • SPAs with data loading needs and client-side routing
  • Apps where you want route-level loaders/actions but control your own bundling
  • Projects not ready for Framework Mode but outgrowing Declarative Mode

When NOT to use:

  • If you only need URL matching and <Link> — Declarative Mode is simpler
  • If you want SSR, streaming, or file-based routing — Framework Mode or an SSR framework is better
  • If your app has no data loading — the overhead of Data Mode is not justified

</philosophy>

<patterns>

Core Patterns

Pattern 1: Data Mode Setup

Define routes as objects with createBrowserRouter. Pass the router to <RouterProvider>. This is the entry point for all Data Mode features.

import { createBrowserRouter, RouterProvider } from "react-router";
import { RootLayout } from "./layouts/root-layout";
import { HomePage } from "./pages/home";
import { PostsPage, postsLoader } from "./pages/posts";

const router = createBrowserRouter([
  {
    path: "/",
    element: <RootLayout />,
    errorElement: <RootError />,
    children: [
      { index: true, element: <HomePage /> },
      {
        path: "posts",
        element: <PostsPage />,
        loader: postsLoader,
      },
    ],
  },
]);

function App() {
  return <RouterProvider router={router} />;
}

Why: Route config lives outside React rendering, enabling the router to call loaders before components mount. errorElement at the root catches any unhandled error in the tree.

See [examples/core.md](examples/core.md) for complete setup with nested routes and error handling.

Pattern 2: Loaders and Actions

Loaders fetch data before the route renders. Actions handle form mutations. Both receive { request, params }. After an action completes, all active loaders automatically revalidate.

// Loader: runs before render
export async function postsLoader() {
  const response = await fetch("/api/posts");
  if (!response.ok) throw new Response("Failed to load", { status: 500 });
  return response.json(); // or return { posts: await response.json() }
}

// Action: handles Form submissions
export async function createPostAction({ request }: ActionFunctionArgs) {
  const formData = await request.formData();
  const title = formData.get("title") as string;
  const post = await createPost({ title });
  return redirect(`/posts/${post.id}`);
}

// Route config
{
  path: "posts",
  element: <PostsPage />,
  loader: postsLoader,
  action: createPostAction,
}

Why: Loaders run in parallel for sibling routes — no waterfall. Actions revalidate all active loaders automatically, keeping the UI in sync. Throwing a Response from a loader triggers errorElement.

See [examples/data-loading.md](examples/data-loading.md) for actions, useFetcher, and revalidation patterns.

Pattern 3: Error Boundaries with errorElement

Every route can define errorElement to catch errors from its loader, action, or component. Use useRouteError() to access the error and `isRou

Compartilhar X LinkedIn