Skip to Content
Module 7: Routing & Navigation7.1 Routing Setup

Module 7.1: React Router Setup & Data API

An abstract banner showing "React Router" with two arrows curving, symbolizing navigation within a web application.

🎯 What You’ll Learn

By the end of this module, you’ll master:

  • Client-Side Routing: Understand the navigation mechanism of SPAs (Single Page Applications) that prevents full page reloads.
  • Classic vs Modern: Differentiate and effectively use both BrowserRouter (the classic approach) and createBrowserRouter (the modern approach).
  • Data APIs: Take control of the powerful loader and action duo for efficient data management.
  • Routing Strategy: Build robust nested routes systems within your application.

1. Why React Router?

In traditional web applications, clicking a link typically triggers a full page reload. React Router transforms your application into a SPA (Single Page Application), offering key benefits:

  1. No Reloads: It only changes the inner content, keeping the overall web page intact.
  2. Blazing Speed: Experience a fluid user interface, much like a native mobile application.
  3. Organized Structure: Manage hundreds of application screens in a clear, maintainable way.

A diagram comparing traditional multi-page application (MPA) architecture, which reloads pages, with single-page application (SPA) architecture, which uses client-side routing.

2. Installation

Run the following command to install the library:

npm install react-router-dom # or yarn add react-router-dom # or pnpm add react-router-dom # or bun add react-router-dom

3. Router Setup

A visual representation of setting up a router, showing a main.tsx file configuring the router and then rendering the main App component.

You have two primary approaches for setting up your Router. Your choice often depends on your project’s scale and specific needs.

3.1 Method 1: Classic Approach (BrowserRouter)

This is the traditional method, configured using JSX. It’s easy to learn, making it perfect for beginners or smaller projects that don’t require Data APIs.

Step 1: Wrap Your App in main.tsx

import { BrowserRouter } from 'react-router-dom'; import App from './App'; ReactDOM.createRoot(document.getElementById('root')!).render( <BrowserRouter> <App /> </BrowserRouter> );

Step 2: Define Routes in App.tsx

import { Routes, Route } from 'react-router-dom'; function App() { return ( <Routes> <Route path="/" element={<Home />}> <Route path="about" element={<About />} /> </Route> </Routes> ); }

3.2 Method 2: Modern Approach (createBrowserRouter)

This is the current standard (as of v6.4) and fully supports Data APIs (loader, action). It helps optimize page load performance by enabling “Render-as-you-fetch” data loading.

import { createBrowserRouter, RouterProvider } from 'react-router-dom'; // Define routes using Objects instead of JSX const router = createBrowserRouter([ { path: '/', element: <HomePage />, children: [{ path: 'about', element: <AboutPage /> }], }, ]); ReactDOM.createRoot(document.getElementById('root')!).render(<RouterProvider router={router} />);

3.3 Comparison (BrowserRouter vs createBrowserRouter)

CriteriaBrowserRouter (Classic)createBrowserRouter (Data Router)
ConfigurationJSX Component (<Route>)Javascript Objects ([])
Data FetchingManual (useEffect)Automatic (loader)
Error HandlingManual (try/catch)Automatic (errorElement)
PerformanceLower (Waterfall)Higher (Parallel Fetching)
Recommended forLearning, Small ProjectsProduction, Real-world Projects

4. Core Concepts

A diagram illustrating nested routes, showing how a parent route can have child routes that render within an Outlet.

4.1 Route Object & Nesting

Nesting routes allows you to create shared Layouts. The child component then renders at the <Outlet /> position defined in its parent.

// Layout export default function RootLayout() { return ( <div> <NavBar /> <Outlet /> {/* This is where the changing content appears */} </div> ); }

4.2 Loader (Fetch Data) - Only with createBrowserRouter

The Old Way (useEffect - Fetch-on-Render): The component first renders (with an empty state) -> runs Effect -> calls API -> data arrives -> re-renders. This often causes a “Waterfall” effect, leading to slower perceived load times.

// ❌ Old Way: Lengthy code, manual loading handling function Products() { const [products, setProducts] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { fetch('/api/products') .then((res) => res.json()) .then((data) => { setProducts(data); setLoading(false); }); }, []); if (loading) return <Spinner />; return ( <ul> {products.map((p) => ( <li>{p.name}</li> ))} </ul> ); }

The New Way (loader - Render-as-you-fetch): The Router fetches data IN PARALLEL while the component is loading. By the time the component appears, the data is already available.

// ✅ New Way: Decoupled data fetching logic // 1. Define the Loader (in a separate file or the same file) export const productLoader = async () => { const res = await fetch('/api/products'); return res.json(); }; // 2. Assign to the Route (router.tsx) { path: 'products', element: <Products />, loader: productLoader, } // 3. Utilize in the Component (Products.tsx) import { useLoaderData } from 'react-router-dom'; function Products() { const products = useLoaderData(); // Data is already available! return ( <ul> {products.map((p: any) => ( <li key={p.id}>{p.name}</li> ))} </ul> ); }

4.3 Error Element (Error Handling)

If an error occurs (e.g., 404, 500), errorElement will display an alternative component, preventing your application from showing a “blank page”.

{ path: '/', element: <RootLayout />, errorElement: <ErrorPage />, }

5. Navigation & UI Hooks

A diagram showing various navigation hooks and components in React Router, including Link, NavLink, useNavigate, useParams, useLocation, and useNavigation.

  • Use <Link> to navigate between pages without a full reload.
  • Use <NavLink> for menus to automatically apply active styles based on the current route.
<NavLink to="/dashboard" className={({ isActive }) => (isActive ? 'active' : '')}> Dashboard </NavLink>

5.2 useNavigate (Programmatic Navigation)

Use this hook when you need to navigate after an action, such as a successful login or form submission.

const navigate = useNavigate(); // ... navigate('/dashboard'); // Navigate to the dashboard navigate(-1); // Go back to the previous page

5.3 useParams (Extract URL Parameters)

Extract dynamic values from the URL. For example, if your route is /products/:productId.

const { productId } = useParams(); // URL: /products/123 -> productId = "123"

5.4 useLocation (Current URL Information)

Get all information about the current URL, including pathname, search params, hash, and state.

const location = useLocation(); console.log(location.pathname); // "/products" console.log(location.search); // "?sort=asc"

5.5 useNavigation (Loading State)

Check the global page loading state (only works with createBrowserRouter).

const navigation = useNavigation(); if (navigation.state === 'loading') return <Spinner />;

6. Labs

We’ll practice both methods, giving you flexibility in any scenario.

Lab 1: “The Zen Portfolio” (Classic BrowserRouter)

Practice Basic Routing with the familiar JSX structure.

  • Technical Goals:
    • Use BrowserRouter to wrap the application.
    • Define nested routes using <Routes> and <Route>.
    • Utilize <NavLink> for a Sidebar and <Outlet> to display content.
  • UI Concept: Minimalist, Typography-driven.

A screenshot of "The Zen Portfolio" lab, featuring a clean, minimalist portfolio UI with a sidebar navigation.

Lab 2: “Crypto Nexus” (Modern Data Router)

Upgrade to the Data Router to build a professional financial Dashboard.

  • Technical Goals:
    • Shift your mindset to createBrowserRouter (Objects).
    • Use loader to fetch Coin prices in parallel.
    • Utilize useNavigation as a Global Loading Bar.
    • Handle API errors with errorElement.
  • UI Concept: Dark Mode, Glassmorphism, Neon Accents.

A screenshot of "Crypto Nexus" lab, displaying a dark-themed cryptocurrency dashboard with glassmorphism elements and neon accents.

7. Summary

FeatureBrief Description
BrowserRouterClassic router, suitable for simpler projects.
createBrowserRouterModern router, supports powerful Data APIs.
loaderEnables early data fetching (Render-as-you-fetch).
<Outlet />The display position for nested routes.
<NavLink />A smart link that understands its active state.

8. Resources

Last updated on