React Router Basics

Introduction

React Router adds client-side routing—change URLs without full page reloads and render different components per path. This chapter installs React Router, configures createBrowserRouter, uses Link / NavLink, dynamic params, and programmatic navigation with useNavigate.

Prerequisites

Install

bash
npm install react-router-dom

Router Setup

src/router.tsx:

src/main.tsx:

tsx
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { RouterProvider } from "react-router-dom";
import { router } from "./router";
import "./index.css";
 
createRoot(document.getElementById("root")!).render(
  <StrictMode>
    <RouterProvider router={router} />
  </StrictMode>
);

Code explanation:

  • createBrowserRouter uses the History API—real URLs like /about
  • RouterProvider renders matched routes
  • Production needs server try_files fallback—Build and Deploy

Compare Vue Router Basics and History API.

Layout with Outlet

src/layouts/RootLayout.tsx:

<Outlet /> renders the active child route—like Vue <RouterView>.

tsx
import { NavLink } from "react-router-dom";
 
<NavLink
  to="/about"
  className={({ isActive }) => (isActive ? "nav active" : "nav")}
>
  About
</NavLink>

Dynamic Params

src/pages/PostDetailPage.tsx:

tsx
import { useParams } from "react-router-dom";
 
export function PostDetailPage() {
  const { slug } = useParams<{ slug: string }>();
 
  return <h1>Post: {slug}</h1>;
}

Navigate programmatically:

tsx
import { useNavigate } from "react-router-dom";
 
function SearchResult({ slug }: { slug: string }) {
  const navigate = useNavigate();
 
  return (
    <button type="button" onClick={() => navigate(`/posts/${slug}`)}>
      Open post
    </button>
  );
}

With state:

tsx
navigate("/checkout", { state: { from: "cart" } });

Read with useLocation().state.

Query Strings

tsx
import { useSearchParams } from "react-router-dom";
 
function PostList() {
  const [searchParams, setSearchParams] = useSearchParams();
  const page = Number(searchParams.get("page") ?? "1");
 
  function goToPage(next: number) {
    setSearchParams({ page: String(next) });
  }
 
  return <p>Page {page}</p>;
}

404 Route

tsx
{
  path: "*",
  element: <NotFoundPage />,
}

Place catch-all last in the route tree.

Route Object Fields

FieldPurpose
pathURL segment
elementComponent to render
childrenNested routes
index: trueDefault child at parent path
loaderData before render — chapter 14

FAQ

HashRouter vs BrowserRouter?

HashRouter (#/about) needs no server config—legacy hosting. Prefer createBrowserRouter for modern SPAs.

tsx
<Link to="settings">Settings</Link>  // relative to current route

Multiple routers?

One RouterProvider per app.

React Router in tests?

Wrap with MemoryRouterTesting.

Next chapter?

Router Guards, Lazy Routes, and Suspense.