DevPath · Learn to code ESPTEN

Routing, testing and patterns

Routing with React Router (conceptual)

Why a router?

A React application is, by default, an SPA (single-page application): a single HTML page whose content changes with JavaScript. So that different URLs (/, /products, /products/42) show different views without reloading the page, a routing library is used. The most widespread one is React Router.

In these exercises the router is not available at runtime: this lesson is conceptual. You will learn to read and reason about the code; the routing checks are done with quizzes.

Defining the routes: <BrowserRouter>, <Routes> and <Route>

You wrap the application in a <BrowserRouter> and declare the routes with <Routes> and <Route>. Each <Route> associates a path with a component through the element prop:

import { BrowserRouter, Routes, Route } from "react-router-dom";

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/products" element={<Products />} />
        <Route path="/products/:id" element={<Product />} />
      </Routes>
    </BrowserRouter>
  );
}

The router watches the browser URL and renders the element of the first route that matches. Switching views does not reload the page: only the React subtree is swapped, preserving the state of the rest of the SPA.

Navigate without reloading: <Link>

To move between routes we use <Link> instead of a normal <a>. An <a href> would cause a full page reload; <Link> changes the URL and lets the router swap the view:

import { Link } from "react-router-dom";

function Menu() {
  return (
    <nav>
      <Link to="/">Home</Link>
      <Link to="/products">Products</Link>
    </nav>
  );
}

Route parameters: useParams

Notice path="/products/:id": the dynamic segments start with :. Inside the component of that route, the useParams hook returns an object with those parameters taken from the URL:

import { useParams } from "react-router-dom";

function Product() {
  const { id } = useParams(); // on /products/42 → id === "42"
  return <h1>Product number {id}</h1>;
}

This way, a single route and a single component serve infinitely many product pages.

Navigate by code: useNavigate

Sometimes you don't want a link, but to navigate as a consequence of an action (after submitting a form, on login...). For that there is the useNavigate hook, which returns a function:

import { useNavigate } from "react-router-dom";

function LoginForm() {
  const navigate = useNavigate();

  function onSubmit() {
    // ...login logic...
    navigate("/dashboard"); // redirects to /dashboard
  }

  return <button onClick={onSubmit}>Sign in</button>;
}

Mental summary: <Route> declares what is shown at each URL, <Link> and useNavigate change the URL, and useParams reads the dynamic pieces.

Put this into practice

DevPath is a hands-on course: you read the theory here; in the app you put it into practice with exercises that really run, offline.

Start free in the app →
Component testing with React Testing Library →