Module 7.1: React Router Setup & Data API

🎯 What You’ll Learn
By the end of this module, you’ll master:
- Client-Side Routing: Understand the navigation
mechanismof SPAs (Single Page Applications) that prevents full page reloads. - Classic vs Modern: Differentiate and effectively use both
BrowserRouter(the classic approach) andcreateBrowserRouter(the modern approach). - Data APIs: Take control of the powerful
loaderandactionduo for efficient data management. - Routing Strategy: Build robust
nested routessystems within yourapplication.
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:
- No Reloads: It only changes the inner content, keeping the overall web page intact.
- Blazing Speed: Experience a fluid user interface, much like a native mobile
application. - Organized Structure: Manage hundreds of
applicationscreens in a clear, maintainable way.

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-dom3. Router Setup

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)
| Criteria | BrowserRouter (Classic) | createBrowserRouter (Data Router) |
|---|---|---|
| Configuration | JSX Component (<Route>) | Javascript Objects ([]) |
| Data Fetching | Manual (useEffect) | Automatic (loader) |
| Error Handling | Manual (try/catch) | Automatic (errorElement) |
| Performance | Lower (Waterfall) | Higher (Parallel Fetching) |
| Recommended for | Learning, Small Projects | Production, Real-world Projects |
4. Core Concepts

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

5.1 <Link> & <NavLink>
- Use
<Link>tonavigatebetween pages without a full reload. - Use
<NavLink>for menus to automatically applyactivestyles based on the currentroute.
<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 page5.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
BrowserRouterto wrap theapplication. - Define
nested routesusing<Routes>and<Route>. - Utilize
<NavLink>for a Sidebar and<Outlet>to display content.
- Use
- UI Concept: Minimalist, Typography-driven.

Lab 2: “Crypto Nexus” (Modern Data Router)
Upgrade to the Data Router to build a professional financial Dashboard.
- Technical Goals:
- Shift your
mindsettocreateBrowserRouter(Objects). - Use
loaderto fetch Coin prices in parallel. - Utilize
useNavigationas a Global Loading Bar. - Handle API errors with
errorElement.
- Shift your
- UI Concept: Dark Mode, Glassmorphism, Neon Accents.

7. Summary
| Feature | Brief Description |
|---|---|
BrowserRouter | Classic router, suitable for simpler projects. |
createBrowserRouter | Modern router, supports powerful Data APIs. |
loader | Enables early data fetching (Render-as-you-fetch). |
<Outlet /> | The display position for nested routes. |
<NavLink /> | A smart link that understands its active state. |