DEV Community

Cover image for React Mastery Series – Day 19: Routing in React – Building Single Page Applications with React Router
Siva Samanthapudi
Siva Samanthapudi

Posted on

React Mastery Series – Day 19: Routing in React – Building Single Page Applications with React Router

Welcome back to the React Mastery Series!

In the previous article, we explored Custom Hooks in React and learned how reusable logic helps developers build scalable and maintainable applications.

Today, we will explore one of the most important concepts in modern frontend development:

React Routing

Almost every real-world React application contains multiple screens:

  • Login
  • Dashboard
  • Profile
  • Settings
  • Reports
  • Transactions
  • Admin panels

But React applications are usually built as:

Single Page Applications (SPA)

So how do we navigate between different pages without refreshing the browser?

The answer is React Router


What is Client-Side Routing?

Traditional websites work like this:

User Clicks Link
       |
       ↓
Browser Requests New HTML Page
       |
       ↓
Server Sends Page
       |
       ↓
Browser Reloads
Enter fullscreen mode Exit fullscreen mode

Every navigation causes a full page refresh.


React Single Page Applications work differently:

User Clicks Link
       |
       ↓
React Router Intercepts Request
       |
       ↓
URL Changes
       |
       ↓
React Loads Component
       |
       ↓
No Page Refresh
Enter fullscreen mode Exit fullscreen mode

This creates a smooth application experience.


What is React Router?

React Router is a library that enables navigation between different components based on the URL.

Example:

/login
/dashboard
/profile
/settings
Enter fullscreen mode Exit fullscreen mode

Each URL maps to a React component.

Example:

/login
   |
   ↓
Login Component


/dashboard
   |
   ↓
Dashboard Component
Enter fullscreen mode Exit fullscreen mode

Installing React Router

For a React application:

npm install react-router-dom
Enter fullscreen mode Exit fullscreen mode

The package provides:

  • BrowserRouter
  • Routes
  • Route
  • Link
  • Navigate
  • useNavigate
  • useParams

Setting Up BrowserRouter

The first step is wrapping your application.

Example:

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

import App from "./App";

ReactDOM.createRoot(document.getElementById("root")).render(
  <BrowserRouter>
    <App />
  </BrowserRouter>,
);

Enter fullscreen mode Exit fullscreen mode

Now React can manage browser navigation.


Creating Routes

Routes define which component should display for a URL.

Example:

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

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

      <Route path="/login" element={<Login />} />

      <Route path="/dashboard" element={<Dashboard />} />
    </Routes>
  );
}

Enter fullscreen mode Exit fullscreen mode

Now:

/login
Enter fullscreen mode Exit fullscreen mode

renders:

<Login />
Enter fullscreen mode Exit fullscreen mode

Understanding Route Components

Example:

<Route path="/profile" element={<Profile />} />;
Enter fullscreen mode Exit fullscreen mode

Contains path and element

The URL path specifies the url appeared in browser

Example:

/profile
Enter fullscreen mode Exit fullscreen mode

element

The component to render on visiting the path specified.

Example:

<Profile />
Enter fullscreen mode Exit fullscreen mode

Navigation Using Link

Traditional HTML - causes a browser refresh.

<a href="/dashboard"> Dashboard </a>
Enter fullscreen mode Exit fullscreen mode

React Router provides:

import { Link } from "react-router-dom";
<Link to="/dashboard">Dashboard</Link>
Enter fullscreen mode Exit fullscreen mode

Benefits:

  • No page refresh
  • SPA behavior
  • Better performance

Creating a Navigation Bar

Example:

function Navbar() {
  return (
    <nav>
      <Link to="/">Home</Link>

      <Link to="/dashboard">Dashboard</Link>

      <Link to="/profile">Profile</Link>
    </nav>
  );
}

Enter fullscreen mode Exit fullscreen mode

When users click:

Dashboard
Enter fullscreen mode Exit fullscreen mode

React loads:

<Dashboard />
Enter fullscreen mode Exit fullscreen mode

without refreshing.


Programmatic Navigation with useNavigate

Sometimes navigation happens after an action.

Examples:

  • Successful login
  • Logout
  • Form submission

Example:

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

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

  function handleLogin() {
    // API success

    navigate("/dashboard");
  }

  return <button onClick={handleLogin}>Login</button>;
}
Enter fullscreen mode Exit fullscreen mode

Flow:

User Login
     |
     ↓
API Success
     |
     ↓
navigate("/dashboard")
     |
     ↓
Dashboard Page
Enter fullscreen mode Exit fullscreen mode

Route Parameters

Many applications need dynamic URLs.

Example:

/users/101
Enter fullscreen mode Exit fullscreen mode

Here:

101
Enter fullscreen mode Exit fullscreen mode

is dynamic.

React Router supports this using parameters.

Example:

<Route path="/users/:id" element={<UserDetails />} />
Enter fullscreen mode Exit fullscreen mode

Reading Route Parameters

Using:

useParams()
Enter fullscreen mode Exit fullscreen mode

Example:

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

function UserDetails() {
  const { id } = useParams();

  return <h2>User ID: {id}</h2>;
}
Enter fullscreen mode Exit fullscreen mode

URL:

/users/101
Enter fullscreen mode Exit fullscreen mode

Output:

User ID: 101
Enter fullscreen mode Exit fullscreen mode

Real-World Example: Banking Application

Consider:

/accounts/12345
Enter fullscreen mode Exit fullscreen mode

where:

12345
Enter fullscreen mode Exit fullscreen mode

is the account number.

Route:

<Route path="/accounts/:accountId" element={<AccountDetails />} />
Enter fullscreen mode Exit fullscreen mode

Component:

const { accountId }=useParams();
Enter fullscreen mode Exit fullscreen mode

Now the application knows which account to display.


Nested Routes

Large applications often have sections inside sections.

Example:

Dashboard

   |
   ├── Overview

   ├── Transactions

   └── Profile
Enter fullscreen mode Exit fullscreen mode

Routes:

<Route>
  <Route path="/dashboard" element={<Dashboard />} >
  <Route path="transactions" element={<Transactions />} />
  <Route path="profile" element={<Profile />} />
</Routes>
Enter fullscreen mode Exit fullscreen mode

URL:

/dashboard/transactions
Enter fullscreen mode Exit fullscreen mode

renders:

Dashboard
    +
Transactions
Enter fullscreen mode Exit fullscreen mode

Outlet Component

Nested routes use:

<Outlet />
Enter fullscreen mode Exit fullscreen mode

Example:

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

function Dashboard() {
  return (
    <div>
      <h1>Dashboard</h1>

      <Outlet />
    </div>
  );
}

Enter fullscreen mode Exit fullscreen mode

The child route appears where Outlet exists.


Protected Routes

Enterprise applications often require authentication.

Example:

Users should access:

/dashboard
Enter fullscreen mode Exit fullscreen mode

only after login.

Without authentication:

/dashboard
       |
       ↓
Redirect
       |
       ↓
/login
Enter fullscreen mode Exit fullscreen mode

Creating ProtectedRoute

Example:

function ProtectedRoute({ children }) {
  const isAuthenticated = true;

  if (!isAuthenticated) {
    return <Navigate to="/login" />;
  }

  return children;
}

Enter fullscreen mode Exit fullscreen mode

Usage:

<Route
  path="/dashboard"

  element={
    <ProtectedRoute>
      <Dashboard />
    </ProtectedRoute>
  }
/>;

Enter fullscreen mode Exit fullscreen mode

Real-World Authentication Flow

Enterprise applications usually follow:

User Opens Application

        |
        ↓

Check Token

        |
        ↓

Token Exists?

        |
   -------------
   |           |
 Yes           No
   |            |
Dashboard     Login
Enter fullscreen mode Exit fullscreen mode

React Router handles navigation decisions.


Lazy Loading Routes

Large applications should not load every page immediately.

Example:

const Dashboard = lazy(() => import("./Dashboard") );
Enter fullscreen mode Exit fullscreen mode

Route:

<Suspense fallback="Loading...">
  <Routes>
    <Route path="/dashboard" element={<Dashboard />} />
  </Routes>
</Suspense>;

Enter fullscreen mode Exit fullscreen mode

Benefits:

  • Smaller initial bundle
  • Faster startup
  • Better performance

Route Organization in Enterprise Projects

A scalable structure:

src

├── routes
│    ├── AppRoutes.jsx
│    ├── ProtectedRoute.jsx
├── pages
│    ├── Login.jsx
│    ├── Dashboard.jsx
│    └── Profile.jsx
├── layouts
│    └── MainLayout.jsx
Enter fullscreen mode Exit fullscreen mode

Real-World Banking Application Routing

Example:

/login

/dashboard

/accounts

/accounts/:id

/transactions

/profile

/settings
Enter fullscreen mode Exit fullscreen mode

Flow:

Login
 |
 ↓
Authentication Success
 |
 ↓
Dashboard
 |
 ├── Accounts
 |
 ├── Transactions
 |
 └── Profile
Enter fullscreen mode Exit fullscreen mode

This is the architecture used in many enterprise React applications.


Common Mistakes

1. Using Anchor Tags

Avoid:

<a href="/dashboard"> Dashboard </a>
Enter fullscreen mode Exit fullscreen mode

Use:

<Link to="/dashboard"> Dashboard </Link>
Enter fullscreen mode Exit fullscreen mode

2. Forgetting BrowserRouter

Without:

<BrowserRouter>
Enter fullscreen mode Exit fullscreen mode

routing will not work.


3. Incorrect Nested Routes

Parent route must contain:

<Outlet />
Enter fullscreen mode Exit fullscreen mode

otherwise child routes won't appear.


4. Loading All Pages at Startup

Large applications should use:

  • lazy loading
  • code splitting

Best Practices

  • Keep routes centralized.
  • Use lazy loading for large applications.
  • Create reusable protected routes.
  • Use meaningful URL structures.
  • Avoid unnecessary route nesting.
  • Separate page components from reusable components.

Key Takeaways

Today, we learned:

✅ React Router enables navigation in Single Page Applications.
✅ Routes map URLs to React components.
Link provides SPA navigation without refresh.
useNavigate enables programmatic navigation.
useParams reads dynamic route values.
✅ Protected routes secure application pages.
✅ Lazy loading improves application performance.


Coming Next 🚀

In Day 20, we will explore:

Building Production-Ready React Applications – Project Structure and Architecture

We will learn:

  • Scalable folder structure
  • Component organization
  • Feature-based architecture
  • Separation of concerns
  • API service layers
  • Error handling
  • Environment configuration
  • Enterprise React project patterns

This will connect all the concepts we learned so far into a real-world production architecture.

Happy Coding! 🚀

Top comments (0)