React routing cheatsheet.
React Router 7
npm i react-router
import { BrowserRouter, Routes, Route, Link, useParams } from "react-router";
function App() {
return (
<BrowserRouter>
<nav>
<Link to="/">Home</Link>
<Link to="/users/1">User 1</Link>
</nav>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/users/:id" element={<User />} />
<Route path="*" element={<NotFound />} />
</Routes>
</BrowserRouter>
);
}
function User() {
const { id } = useParams();
return <p>User {id}</p>;
}
Nested routes
<Route path="/users" element={<UsersLayout />}>
<Route index element={<UsersList />} />
<Route path=":id" element={<UserDetail />} />
</Route>
<Outlet /> in UsersLayout renders matched child.
Programmatic nav
import { useNavigate } from "react-router";
const nav = useNavigate();
nav("/users/1");
nav(-1); // back
nav("/x", { replace: true });
Search params
import { useSearchParams } from "react-router";
const [params, setParams] = useSearchParams();
const q = params.get("q");
setParams({ q: "hello" });
Loaders (data router)
import { createBrowserRouter, RouterProvider } from "react-router";
const router = createBrowserRouter([
{
path: "/",
element: <Layout />,
loader: async () => fetchSession(),
children: [
{
path: "users/:id",
element: <User />,
loader: async ({ params }) => fetchUser(params.id),
},
],
},
]);
<RouterProvider router={router} />
// In component:
const user = useLoaderData<typeof loader>();
Data is pre-fetched in parallel with code splitting.
Actions
{
path: "users/:id",
element: <UserEdit />,
action: async ({ request, params }) => {
const form = await request.formData();
await updateUser(params.id, form);
return redirect(`/users/${params.id}`);
},
}
// Component:
<Form method="post">
<input name="name" />
<button>Save</button>
</Form>
TanStack Router (typed)
npm i @tanstack/react-router
import { Router, Route, RootRoute, Link } from "@tanstack/react-router";
const root = new RootRoute({ component: () => <Outlet /> });
const home = new Route({ getParentRoute: () => root, path: "/", component: Home });
const user = new Route({
getParentRoute: () => root,
path: "users/$id",
loader: ({ params }) => fetchUser(params.id),
component: User,
});
const tree = root.addChildren([home, user]);
const router = new Router({ routeTree: tree });
// In User component:
const { id } = userRoute.useParams();
const data = userRoute.useLoaderData();
Routes are fully typed: params, search, loader data — all checked.
File-based routing
npm i @tanstack/router-plugin
src/routes/
├── __root.tsx
├── index.tsx
├── users.tsx # /users
└── users.$id.tsx # /users/:id
Generates the tree at build time.
Search params (typed)
const route = new Route({
validateSearch: z.object({ q: z.string().optional() }),
});
const { q } = route.useSearch();
Search params are validated and typed.
Link prefetching
<Link to="/users/$id" params={{ id: "1" }} preload="intent">
User 1
</Link>
Prefetches data on hover/focus.
Outlets
import { Outlet } from "react-router"; // or tanstack
function Layout() {
return (
<div>
<Sidebar />
<main><Outlet /></main>
</div>
);
}
Lazy routes
{
path: "settings",
lazy: async () => {
const m = await import("./Settings");
return { Component: m.default };
},
}
Reduces initial bundle.
Active link
import { NavLink } from "react-router";
<NavLink to="/" className={({ isActive }) => isActive ? "current" : ""}>
Home
</NavLink>
Protected routes
function RequireAuth({ children }: { children: React.ReactNode }) {
const { user } = useAuth();
if (!user) return <Navigate to="/login" />;
return <>{children}</>;
}
<Route path="/dashboard" element={
<RequireAuth><Dashboard /></RequireAuth>
} />
Or use a loader:
{
path: "dashboard",
loader: async () => {
const user = await getUser();
if (!user) throw redirect("/login");
return user;
},
}
Common mistakes
- Using
useEffectto fetch route data — use loaders. - Mixing
<Switch>(v5) with v7 syntax — different paradigm. - Forgetting
<Outlet />in layout — children won’t show. - Path
users/:idwithout leading slash — relative path matters. - Setting search params on every render — infinite loop.
Read this next
If you want my router + auth setup, it’s at rajpoot.dev .
Building something AI-, backend-, or data-heavy and want a second pair of eyes? I do consulting and freelance work — see my projects and ways to reach me at rajpoot.dev .