Getting Started with React Router

For more detailed information and advanced usage, refer to the official React Router documentation.

React Router is a standard library for routing in React applications.
It enables the navigation among views of various components in a React application, allows changing the browser URL, and keeps the UI in sync with the URL.

Introduction

Let’s analyze “Browser Router” and then explore React Router in depth to help you get started.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import React from 'react';
import { BrowserRouter as Router, Route, Routes, Link, useNavigate } from 'react-router-dom';
import HomePage from './components/HomePage';
import EditorPage from './components/EditorPage';
import './App.css';

function App() {
return (
<Router>
<div className="App min-h-screen bg-gray-50">
<NavBar />
<main>
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/editor/:id" element={<EditorPage />} />
</Routes>
</main>
<Footer />
</div>
</Router>
);
}

This code is implementing the Browser Router pattern in React Router v6, which uses the HTML5 history API to keep your UI in sync with the URL.

React Router Basics

Installation

To use React Router in your project, install it using npm or yarn:

1
2
3
npm install react-router-dom
# or
yarn add react-router-dom

Router Types

React Router offers several router types, each suited for different environments:

1. BrowserRouter

The BrowserRouter uses the HTML5 history API (pushState, replaceState, and the popstate event) to keep your UI in sync with the URL.

1
2
3
4
5
6
7
8
9
import { BrowserRouter } from 'react-router-dom';

function App() {
return (
<BrowserRouter>
{/* Your routes go here */}
</BrowserRouter>
);
}

2. HashRouter

The HashRouter uses the hash portion of the URL (i.e., window.location.hash) to keep your UI in sync with the URL.

1
2
3
4
5
6
7
8
9
import { HashRouter } from 'react-router-dom';

function App() {
return (
<HashRouter>
{/* Your routes go here */}
</HashRouter>
);
}

3. MemoryRouter

The MemoryRouter keeps the history of your “URL” in memory (does not read or write to the address bar). Useful for testing and non-browser environments like React Native.

1
2
3
4
5
6
7
8
9
import { MemoryRouter } from 'react-router-dom';

function App() {
return (
<MemoryRouter>
{/* Your routes go here */}
</MemoryRouter>
);
}

Route Configuration in React Router v6

In your code, you’re using the v6 pattern with the Routes and Route components.

Routes Component

The Routes component replaced the old Switch component from v5. It’s responsible for rendering the first Route that matches the current URL.

Route Component

The Route component defines a path and the element to render when that path matches the current URL.

1
2
3
4
5
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/about" element={<AboutPage />} />
<Route path="/contact" element={<ContactPage />} />
</Routes>

URL Parameters

In your code, you have a dynamic route: /editor/:id. The :id is a URL parameter that can be accessed in the component using the useParams hook.

1
2
3
4
5
6
7
8
9
10
11
12
import { useParams } from 'react-router-dom';

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

return (
<div>
<h1>Editor for document with ID: {id}</h1>
{/* Rest of your component */}
</div>
);
}

Advanced Routing Techniques

Nested Routes

React Router v6 allows you to nest routes, which is useful for layouts and more complex route hierarchies:

1
2
3
4
5
6
7
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<Home />} />
<Route path="about" element={<About />} />
<Route path="dashboard" element={<Dashboard />} />
</Route>
</Routes>

In the layout component, you would use the Outlet component to specify where the nested content should be rendered:

1
2
3
4
5
6
7
8
9
10
11
12
13
import { Outlet } from 'react-router-dom';

function Layout() {
return (
<div>
<header>Header content</header>
<main>
<Outlet /> {/* Nested route components render here */}
</main>
<footer>Footer content</footer>
</div>
);
}

React Router provides several ways to navigate:

The Link component creates an anchor tag that navigates to a specified route without reloading the page:

1
2
3
4
5
6
7
8
9
10
11
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>
);
}

Similar to Link, but provides styling options when the link is active:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { NavLink } from 'react-router-dom';

function NavBar() {
return (
<nav>
<NavLink
to="/"
className={({ isActive }) => isActive ? "active-link" : ""}
>
Home
</NavLink>
{/* More links */}
</nav>
);
}

3. Programmatic Navigation with useNavigate

The useNavigate hook allows for programmatic navigation:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { useNavigate } from 'react-router-dom';

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

const handleCreate = () => {
const id = uuidv4(); // Generate a unique ID
navigate(`/editor/${id}`); // Navigate to the editor with this ID
};

return (
<button onClick={handleCreate}>Create New Document</button>
);
}

Route Protection

You can create protected routes that only authenticated users can access:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function RequireAuth({ children }) {
const auth = useAuth(); // Your authentication context or hook
const navigate = useNavigate();

if (!auth.user) {
// Redirect to login page if not authenticated
return <Navigate to="/login" />;
}

return children;
}

// Usage
<Routes>
<Route path="/login" element={<LoginPage />} />
<Route
path="/admin"
element={
<RequireAuth>
<AdminDashboard />
</RequireAuth>
}
/>
</Routes>

Lazy Loading

For better performance, you can use React’s lazy loading with React Router:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import React, { Suspense, lazy } from 'react';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';

const Home = lazy(() => import('./components/Home'));
const About = lazy(() => import('./components/About'));

function App() {
return (
<Router>
<Suspense fallback={<div>Loading...</div>}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</Suspense>
</Router>
);
}

Common Patterns and Best Practices

404 Pages

Handle unknown routes with a catch-all route at the end of your Routes:

1
2
3
4
5
6
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
{/* Other routes */}
<Route path="*" element={<NotFound />} />
</Routes>

URL Search Parameters

Use the useSearchParams hook to work with query parameters:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { useSearchParams } from 'react-router-dom';

function ProductList() {
const [searchParams, setSearchParams] = useSearchParams();
const category = searchParams.get('category');

return (
<div>
<h1>Products in category: {category || 'All'}</h1>
<button onClick={() => setSearchParams({ category: 'electronics' })}>
Show Electronics
</button>
{/* Product list */}
</div>
);
}

Location State

Pass additional data during navigation that isn’t reflected in the URL:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// When navigating
navigate('/product', {
state: {
previousPage: 'home',
referrer: 'sidebar'
}
});

// In the target component
import { useLocation } from 'react-router-dom';

function Product() {
const location = useLocation();
const { previousPage, referrer } = location.state || {};

return (
<div>
<p>You came from: {previousPage}</p>
<p>Referrer: {referrer}</p>
{/* Product details */}
</div>
);
}

Getting Started with React Router
https://www.hardyhu.cn/2024/12/31/Getting-Started-with-React-Router/
Author
John Doe
Posted on
December 31, 2024
Licensed under