ReactRoutingbeginner
Updated:

React Router Tutorial for Beginners

7 min read

Add real multi-page navigation to a React app: install React Router, define routes, link between pages, read URL params, and handle nested and 404 routes.

TL;DR – Quick Answer

React Router is the standard library for adding navigation and multiple pages to a React single-page app. You wrap your app in a router, define Route elements that map URL paths to components, and use Link components to move between them without a full page reload. It also supports URL parameters, nested routes, and 404 handling.

On This Page

A React app, by default, is a single HTML page. That is great for speed, but real applications need multiple screens — a home page, a course list, a details page, a login form. React Router is the library that makes those screens work with proper URLs, back-button support, and instant navigation, all without reloading the page from the server.

This tutorial takes you from zero to a working multi-page app. You will install React Router, define routes, link between them, read data from the URL, and handle the "page not found" case. If you are brand new to React, skim what React is first, since routing assumes you are comfortable with components.

Single-page apps and client-side routing

Traditional websites ask the server for a brand-new HTML page every time you click a link. A React single-page application (SPA) loads once, then rewrites the visible content with JavaScript as you navigate. The URL still changes and the back button still works, but no full reload happens — this is client-side routing, and React Router manages it.

The payoff is speed and a smoother feel: shared layout like the navbar stays put, and only the changed part of the screen updates. The cost is that you must wire up routing yourself, which is exactly what React Router makes straightforward.

Installing React Router

React Router ships as the react-router-dom package. Inside your project (created with Vite or similar), install it:

npm install react-router-dom

That single package gives you every routing component and hook used in this guide. If you have not set up a project yet, do that first and come back — you need a running React app to add routes to.

Defining your first routes

Routing has three moving parts: a router that wraps your app, Route definitions that map a URL path to a component, and a Routes wrapper that picks the first match. Here is a complete minimal setup:

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

function Home() {
  return <h2>Home page</h2>;
}

function About() {
  return <h2>About CodeBegun</h2>;
}

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

export default App;

BrowserRouter enables routing for the whole app, so it wraps everything once, usually at the top. Each Route says "when the URL is this path, render this component." Visit / and you see Home; visit /about and you see About. The element prop takes actual JSX, which is why we write <Home /> rather than just Home.

To move between routes, you do not use a normal <a href>, because that reloads the entire page and destroys your app's state. React Router provides Link, which changes the URL and swaps the view instantly on the client.

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

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

export default Navbar;

For navigation links that should highlight the active page, use NavLink instead — it adds an active class automatically when its route is the current one, which is perfect for styling the selected menu item.

Common mistake: Using <a href="/about"> for internal navigation. It works visually but triggers a full server reload, wiping out any state and making the app feel slow. Reserve anchor tags for external links; use Link or NavLink for anything inside your app.

Reading URL parameters

Most real apps have dynamic pages: one component that shows different content depending on the URL, like a course details page for each course id. You declare a dynamic segment with a colon, then read it with the useParams hook.

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

function CourseDetails() {
  const { id } = useParams();
  return <h2>Showing details for course #{id}</h2>;
}

function App() {
  return (
    <Routes>
      <Route path="/course/:id" element={<CourseDetails />} />
    </Routes>
  );
}

export default App;

Now /course/101 and /course/205 render the same component with a different id. In a real app you would use that id to fetch the matching data — often inside a useEffect, which the React hooks introduction covers in detail.

Programmatic navigation

Sometimes you need to navigate in response to logic, not a click — for example, redirecting to a dashboard after a successful login. The useNavigate hook returns a function you call to change routes from code:

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

function LoginButton() {
  const navigate = useNavigate();
  return (
    <button onClick={() => navigate("/dashboard")}>
      Log in
    </button>
  );
}

export default LoginButton;

This pairs naturally with forms: validate input, then call navigate on success. You will see this exact pattern when you build login and signup flows with controlled form components.

Nested routes and shared layouts

Real apps share layout — a navbar and footer that stay constant while the inner content changes. React Router handles this with nested routes and an Outlet, which marks where child routes render inside a parent layout.

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

function Layout() {
  return (
    <div>
      <Navbar />
      <main>
        <Outlet />
      </main>
    </div>
  );
}

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

The Layout renders once; the Outlet is replaced by whichever child route matches. This keeps your navbar and footer from re-mounting on every navigation.

Two everyday needs round out a real app: highlighting the current page and reading query parameters. For highlighting, NavLink is built for the job — it exposes whether it is active so you can style it:

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

<NavLink
  to="/courses"
  className={({ isActive }) => (isActive ? "active" : "")}
>
  Courses
</NavLink>

The function form of className receives an isActive flag, so the current page's link gets the active class automatically. This is how navbars show which section you are on without any manual tracking.

Query strings — the ?sort=price&page=2 part of a URL — are read with the useSearchParams hook, which works much like useState but is backed by the URL:

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

function CourseList() {
  const [params, setParams] = useSearchParams();
  const sort = params.get("sort") || "name";

  return (
    <button onClick={() => setParams({ sort: "price" })}>
      Sorting by: {sort}
    </button>
  );
}

export default CourseList;

Because the state lives in the URL, users can bookmark or share a filtered view, and the back button restores previous filters. This is a genuine advantage of routing-aware state over plain component state, a trade-off discussed in the React state management overview.

Handling 404 pages

To catch URLs that match no route, add a final Route with path="*". React Router uses it as a fallback when nothing else matches:

<Route path="*" element={<h2>404 — Page not found</h2>} />

Place it last inside Routes. Now instead of a blank screen, users who hit a broken or mistyped link get a clear message, and you can add a link back home. A good 404 page keeps people in your app rather than sending them to the browser's error screen, which quietly improves both usability and how long visitors stay.

The order of routes matters more than beginners expect. React Router v6 picks the best match rather than the first match, but keeping the * fallback last and grouping related routes together keeps large route tables readable. As your app grows past a dozen routes, consider splitting them into logical groups and even lazy-loading heavier sections so the initial bundle stays small — a technique that pairs naturally with the performance mindset you build as you advance.

Pro tip: If your app grows into a full-stack project with SEO needs, you may outgrow client-side routing and move to Next.js, whose file-based routing and server rendering are covered in the Next.js introduction. For a client-only SPA, though, React Router remains the right, lightweight choice.

Putting it all together

You now have every piece needed for real navigation: BrowserRouter to enable routing, Routes and Route to map paths, Link and NavLink to navigate, useParams for dynamic pages, useNavigate for programmatic redirects, nested routes with Outlet for shared layouts, and a * route for 404s.

The best way to cement this is to build a small app with four or five pages — home, a list, a details page using a URL param, and a not-found page — and wire the navbar with NavLink. Routing is one of the most job-relevant React skills, so it appears constantly in real projects and on the path mapped out in the how to become a React developer guide. For the full guided sequence, the React learning hub places routing in context with everything else you need.

Frequently Asked Questions

What is React Router used for?
React Router adds client-side navigation to a React app so different URLs render different components, giving the feel of multiple pages in a single-page app. It handles the browser URL, back and forward buttons, links, and dynamic parameters without reloading the whole page from the server.
Why use Link instead of a normal anchor tag?
A plain anchor tag triggers a full page reload, which throws away your app state and re-downloads everything. React Router's Link updates the URL and swaps the view instantly on the client, keeping the app fast and preserving state. Always use Link or NavLink for in-app navigation.
How do I read a URL parameter in React Router?
Define the route path with a colon segment like /course/:id, then call the useParams hook inside the target component to read id from the returned object. This lets one component render different content based on the URL, such as a details page per course.
What is the difference between React Router and Next.js routing?
React Router is a library you add to a client-side React app and configure with code. Next.js has built-in, file-based routing where the folder structure defines the routes, plus server-side rendering. For a plain React SPA you use React Router; for a full-stack React framework you often use Next.js routing.
How do I create a 404 not found page?
Add a Route with the path set to an asterisk as the last route. React Router matches it when no other route matches, so you can render a custom not found component. This gives users a friendly page instead of a blank screen for unknown URLs.

Want to Build Your Career in Java Full Stack with AI?

Join CodeBegun and train with working industry engineers — Explore the Program

Apply for Demo Class →
Siva Prasad Galaba
Founder, CodeBegun · Staff Engineer

Founder of CodeBegun. 15+ years building Java systems at companies like Crunchyroll. Teaches Java, Spring Boot and system design the way the industry actually works, and mentors students through projects, mock interviews and placement preparation.

Technically reviewed by CodeBegun Technical TeamLast reviewed 15 July 2026 LinkedIn
Chat with us