LearnContact
Lesson 3924 min read

React Router

Learn what client-side routing is and how to add multi-page navigation to a React app using react-router-dom.

Introduction

Every React application you have built so far in this course has rendered a single page. Real applications, though, usually need multiple views — a home page, a profile page, a settings page — and users expect to navigate between them with URLs, back/forward buttons, and bookmarks, just like on any traditional website.

React itself has no built-in concept of "pages" or "routes" — remember, it is a UI library, not a full framework. React Router is the standard companion library that adds this capability, letting a single-page application (SPA) show different components based on the current URL, without ever triggering a full page reload.

What You Will Learn
  • What client-side routing is and why an SPA needs a router.
  • How to install react-router-dom into a React project.
  • How to wrap an app in <BrowserRouter> and define <Routes> and <Route>.
  • How to navigate between pages with <Link> instead of a plain <a> tag.

What is Client-Side Routing?

On a traditional multi-page website, clicking a link sends a brand-new request to the server, which sends back a whole new HTML document, and the browser reloads the entire page. Client-side routing works differently: the browser loads the React app once, and afterward a router library intercepts navigation, swaps out which component is displayed, and updates the URL in the address bar — all without contacting the server again.

Traditional (server) routing

  • Click a link → new HTTP request to server
  • Server sends a full new HTML page
  • Browser reloads everything from scratch
  • JavaScript state (e.g. form data) is lost

Client-side routing (React Router)

  • Click a <Link> → router intercepts the click
  • Router swaps which component is rendered
  • URL updates via the browser History API
  • No page reload — app state can be preserved
Why This Matters

Because there is no full page reload, transitions between "pages" feel instant, and any state that lives outside the page-specific component — like a shopping cart or a logged-in user in Context — survives the navigation.

Installing react-router-dom

React Router is not part of React itself, so it is installed as a separate package. The version used for web apps is react-router-dom.

Terminal
npm install react-router-dom
Terminal Output
added 6 packages in 2s

react-router-dom@6.x.x

Once installed, the library exports the pieces you need to define and navigate between routes: BrowserRouter, Routes, Route, and Link, all imported from 'react-router-dom'.

BrowserRouter, Routes, and Route

<BrowserRouter> is the outermost wrapper that enables routing for everything inside it — it should sit near the very top of your component tree, usually wrapping <App />. Inside it, <Routes> looks at the current URL and renders whichever <Route> matches, based on each Route's path prop.

main.jsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import App from './App';

ReactDOM.createRoot(document.getElementById('root')).render(
  <BrowserRouter>
    <App />
  </BrowserRouter>
);
App.jsx
import { Routes, Route } from 'react-router-dom';
import Home from './pages/Home';
import About from './pages/About';
import Contact from './pages/Contact';

function App() {
  return (
    <Routes>
      <Route path="/" element={<Home />} />
      <Route path="/about" element={<About />} />
      <Route path="/contact" element={<Contact />} />
    </Routes>
  );
}

export default App;
Behavior
Visiting  /          → renders <Home />
Visiting  /about     → renders <About />
Visiting  /contact   → renders <Contact />

Only one Route's element renders at a time — whichever path matches the current URL. Everything outside the Routes block (like a shared navbar) renders on every page, since it sits outside the part that gets swapped.

A plain <a href="..."> tag would trigger a full page reload, defeating the purpose of client-side routing. React Router's <Link> component renders an anchor tag under the hood but intercepts the click, updating the URL and swapping components without reloading the page.

Navbar.jsx
import { Link } from 'react-router-dom';

function Navbar() {
  return (
    <nav>
      <Link to="/">Home</Link>
      <Link to="/about">About</Link>
      <Link to="/contact">Contact</Link>
    </nav>
  );
}

export default Navbar;
App.jsx (with Navbar)
import { Routes, Route } from 'react-router-dom';
import Navbar from './Navbar';
import Home from './pages/Home';
import About from './pages/About';
import Contact from './pages/Contact';

function App() {
  return (
    <div>
      <Navbar />
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
        <Route path="/contact" element={<Contact />} />
      </Routes>
    </div>
  );
}

export default App;
Rendered on the Page
Home  About  Contact   ← Navbar links, always visible

(page content below changes based on the URL, no reload)
Never use a plain <a> tag for internal navigation

A plain <a href="/about"> works, but it forces the entire app to reload from the server, discarding your React state and the whole benefit of client-side routing. Always use <Link to="..."> (or <NavLink>) for links that stay inside your app.

Common Mistakes

Avoid These Mistakes
  • Forgetting to wrap the app in <BrowserRouter>, which causes "useNavigate/useParams must be used within a Router" errors.
  • Using a plain <a href> instead of <Link to>, which causes an unwanted full page reload.
  • Placing <Route> components directly without a parent <Routes> wrapper — that syntax belonged to React Router v5, not v6.
  • Forgetting the leading slash in path values, leading to routes that never match as expected.

Best Practices

  • Wrap <BrowserRouter> around the whole app, as close to the root as possible.
  • Keep each route's element pointed at a dedicated page component rather than inline JSX.
  • Put shared UI, like a Navbar or Footer, outside the <Routes> block so it appears on every page.
  • Use <Link> (or <NavLink> for active-state styling) for every internal navigation link.
  • Organize page components in a dedicated pages/ folder to keep routing code easy to scan.

Frequently Asked Questions

Is React Router part of React itself?

No. It is a separate, officially recommended package (react-router-dom) that you install yourself, since React's core library intentionally does not include routing.

What is the difference between BrowserRouter and HashRouter?

BrowserRouter uses clean URLs (like /about) powered by the History API and needs basic server configuration to support direct links. HashRouter uses a # in the URL (like /#/about) and works anywhere without server configuration, at the cost of less clean URLs.

Can I nest <Routes> inside a page component?

Yes — nested routing is a common pattern for pages with their own sub-navigation, and is covered in the next couple of lessons.

Why use <Link> instead of just calling window.location.href?

window.location.href triggers a full browser navigation and page reload. <Link> uses React Router's internal navigation, which is instant and preserves your app's in-memory state.

Do routes have to match the file structure of my project?

No. Route paths are just strings you choose in your <Route> definitions; they do not have to mirror your folder or file names, though keeping them aligned often helps readability.

Key Takeaways

  • Client-side routing lets a React SPA show different views based on the URL without a full page reload.
  • react-router-dom is installed separately and provides BrowserRouter, Routes, Route, and Link.
  • <BrowserRouter> should wrap the app; <Routes> renders whichever <Route> matches the current path.
  • <Link to="..."> replaces plain <a> tags for internal navigation, avoiding unwanted reloads.
  • Shared UI like a navbar sits outside <Routes> so it persists across every page.

Summary

React Router brings multi-page navigation to single-page React applications, letting different components render based on the current URL while keeping transitions instant and state intact. BrowserRouter enables routing, Routes and Route define what shows where, and Link handles navigation without reloading the page.

In this lesson, you installed react-router-dom, wrapped an app in BrowserRouter, defined a handful of routes, and built a navbar using Link. Next, you will learn how to build dynamic routes that read parameters straight out of the URL, like a user's ID on a profile page.

Lesson 39 Completed
  • You understand what client-side routing is and why SPAs need it.
  • You installed react-router-dom into a React project.
  • You can define routes with BrowserRouter, Routes, and Route.
  • You can navigate between pages using Link instead of <a>.
Next Lesson →

Route Parameters