React Router — A Quick Tour

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.

5 min read Level 2/5 #react#react-router#routing
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.

Data Fetching Libraries →