Routes, Links, Params, and Nested Layouts
React Router — A Quick Tour
The 20% of React Router you'll use 80% of the time — `<Routes>`, `<Route>`, `<Link>`, params, and nested routes.
What you'll learn
- Wire up a basic router
- Use `<Link>` instead of `<a>`
- Read URL params with `useParams`
- Nest routes for shared layouts
This is the 20% of React Router (v6+) you’ll use 80% of the time.
Install
npm install react-router-dom Minimal Setup
import { BrowserRouter, Routes, Route, Link } from "react-router-dom";
function App() {
return (
<BrowserRouter>
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
</nav>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</BrowserRouter>
);
} <BrowserRouter>wraps the app — does the history magic<Routes>picks the matching<Route>for the URL<Link>is the SPA-friendly replacement for<a>— it intercepts the click and updates the URL without a reload
URL Params
import { useParams } from "react-router-dom";
<Route path="/users/:id" element={<UserPage />} />
function UserPage() {
const { id } = useParams();
return <p>User #{id}</p>;
} :id is a placeholder — useParams() returns { id: "42" } for
/users/42. Params are always strings; cast if you need a number.
Programmatic Navigation
import { useNavigate } from "react-router-dom";
function LogoutButton() {
const navigate = useNavigate();
return <button onClick={() => navigate("/login")}>Log out</button>;
} Query Params
import { useSearchParams } from "react-router-dom";
function Search() {
const [params, setParams] = useSearchParams();
const q = params.get("q") ?? "";
return (
<input
value={q}
onChange={e => setParams({ q: e.target.value })}
/>
);
} URL updates as the user types. Bookmarkable.
Nested Routes for Shared Layouts
When a section of the app shares a layout (sidebar, header):
<Routes>
<Route path="/dashboard" element={<DashboardLayout />}>
<Route index element={<DashboardHome />} />
<Route path="settings" element={<Settings />} />
<Route path="users/:id" element={<User />} />
</Route>
</Routes>
function DashboardLayout() {
return (
<div>
<Sidebar />
<Outlet /> {/* nested route renders here */}
</div>
);
} <Outlet /> is where the matched child route gets rendered. The
sidebar stays put; the right side swaps based on the URL.
404s
<Routes>
<Route path="/" element={<Home />} />
<Route path="*" element={<NotFound />} />
</Routes> The * route matches anything no other route matched.
What’s Beyond
Data routers (loaders, actions), code-splitting per route, and suspense boundaries are all in React Router’s bigger features. Worth reading once you’re past the basics.
Up Next
For real data fetching, you’ll want more than useEffect + fetch.