React Router Complete Guide | Client-Side Routing for React
이 글의 핵심
React Router is the standard routing library for React applications. It enables navigation between views, URL parameter handling, and data loading for single-page applications.
Introduction
React Router is the standard routing library for React. It enables client-side routing, allowing users to navigate between different views without full page reloads.
Without React Router
function App() {
const [page, setPage] = useState('home');
return (
<div>
<button onClick={() => setPage('home')}>Home</button>
<button onClick={() => setPage('about')}>About</button>
{page === 'home' && <Home />}
{page === 'about' && <About />}
</div>
);
}
Problems:
- ❌ No URL updates
- ❌ No browser back/forward
- ❌ No bookmarking
- ❌ No deep linking
With React Router
import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';
function App() {
return (
<BrowserRouter>
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
</nav>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</BrowserRouter>
);
}
1. Installation
npm install react-router-dom
2. Basic Routing
import { BrowserRouter, Routes, Route } from 'react-router-dom';
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />} />
<Route path="*" element={<NotFound />} />
</Routes>
</BrowserRouter>
);
}
3. Navigation
Link Component
import { Link } from 'react-router-dom';
function Nav() {
return (
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
<Link to="/users/123">User 123</Link>
</nav>
);
}
NavLink (Active Styling)
import { NavLink } from 'react-router-dom';
function Nav() {
return (
<nav>
<NavLink
to="/"
className={({ isActive }) => isActive ? 'active' : ''}
>
Home
</NavLink>
<NavLink
to="/about"
style={({ isActive }) => ({
color: isActive ? 'red' : 'black'
})}
>
About
</NavLink>
</nav>
);
}
Programmatic Navigation
import { useNavigate } from 'react-router-dom';
function LoginForm() {
const navigate = useNavigate();
const handleSubmit = async (e) => {
e.preventDefault();
await login();
navigate('/dashboard'); // Navigate after login
};
return <form onSubmit={handleSubmit}>...</form>;
}
4. URL Parameters
Dynamic Routes
<Routes>
<Route path="/users/:id" element={<UserProfile />} />
<Route path="/posts/:year/:month/:slug" element={<Post />} />
</Routes>
Reading Parameters
import { useParams } from 'react-router-dom';
function UserProfile() {
const { id } = useParams();
return <div>User ID: {id}</div>;
}
Query Strings
import { useSearchParams } from 'react-router-dom';
function SearchPage() {
const [searchParams, setSearchParams] = useSearchParams();
const query = searchParams.get('q');
const page = searchParams.get('page') || '1';
const handleSearch = (newQuery) => {
setSearchParams({ q: newQuery, page: '1' });
};
return (
<div>
<p>Searching for: {query}</p>
<p>Page: {page}</p>
</div>
);
}
5. Nested Routes
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<Home />} />
<Route path="about" element={<About />} />
<Route path="users" element={<Users />}>
<Route index element={<UsersList />} />
<Route path=":id" element={<UserProfile />} />
<Route path=":id/settings" element={<UserSettings />} />
</Route>
</Route>
</Routes>
import { Outlet } from 'react-router-dom';
function Layout() {
return (
<div>
<header>Header</header>
<main>
<Outlet /> {/* Child routes render here */}
</main>
<footer>Footer</footer>
</div>
);
}
6. Data Loading
Loaders (React Router 6.4+)
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
const router = createBrowserRouter([
{
path: '/users/:id',
element: <UserProfile />,
loader: async ({ params }) => {
const res = await fetch(`/api/users/${params.id}`);
return res.json();
},
},
]);
function App() {
return <RouterProvider router={router} />;
}
import { useLoaderData } from 'react-router-dom';
function UserProfile() {
const user = useLoaderData();
return <div>{user.name}</div>;
}
7. Form Actions
const router = createBrowserRouter([
{
path: '/users/:id',
element: <EditUser />,
loader: async ({ params }) => {
const res = await fetch(`/api/users/${params.id}`);
return res.json();
},
action: async ({ request, params }) => {
const formData = await request.formData();
const res = await fetch(`/api/users/${params.id}`, {
method: 'PATCH',
body: JSON.stringify(Object.fromEntries(formData)),
});
return res.json();
},
},
]);
import { Form, useLoaderData } from 'react-router-dom';
function EditUser() {
const user = useLoaderData();
return (
<Form method="post">
<input name="name" defaultValue={user.name} />
<input name="email" defaultValue={user.email} />
<button type="submit">Save</button>
</Form>
);
}
8. Error Handling
const router = createBrowserRouter([
{
path: '/',
element: <Root />,
errorElement: <ErrorPage />,
children: [
{
path: 'users/:id',
element: <UserProfile />,
loader: async ({ params }) => {
const res = await fetch(`/api/users/${params.id}`);
if (!res.ok) throw new Response('Not Found', { status: 404 });
return res.json();
},
},
],
},
]);
import { useRouteError, isRouteErrorResponse } from 'react-router-dom';
function ErrorPage() {
const error = useRouteError();
if (isRouteErrorResponse(error)) {
return (
<div>
<h1>{error.status} {error.statusText}</h1>
<p>{error.data}</p>
</div>
);
}
return <div>Something went wrong!</div>;
}
9. Protected Routes
import { Navigate } from 'react-router-dom';
function ProtectedRoute({ children }) {
const { user } = useAuth();
if (!user) {
return <Navigate to="/login" replace />;
}
return children;
}
// Usage
<Route
path="/dashboard"
element={
<ProtectedRoute>
<Dashboard />
</ProtectedRoute>
}
/>
10. TypeScript Integration
import { useParams, useLoaderData } from 'react-router-dom';
interface User {
id: number;
name: string;
email: string;
}
function UserProfile() {
const { id } = useParams<{ id: string }>();
const user = useLoaderData() as User;
return (
<div>
<h1>{user.name}</h1>
<p>{user.email}</p>
</div>
);
}
Summary
React Router enables powerful client-side routing:
- Declarative routing with JSX
- Nested routes for layouts
- Data loading with loaders
- Form handling with actions
- TypeScript support
Key Takeaways:
- Use
<Link>for navigation useParamsfor URL parameters- Loaders for data fetching
- Actions for mutations
- Nested routes for layouts
Next Steps:
Resources:
Frequently Asked Questions (FAQ)
Q. When would I use this in practice?
A. Complete React Router guide for SPAs. Learn routing, nested routes, loaders, actions, navigation, and building multi-pag…
Q. What should I read before this?
A. Follow the previous article or related articles links at the bottom of each post to learn in sequence.
Q. Where can I study this more deeply?
A. Check cppreference and the relevant library’s official documentation. The reference links at the end of the article are also worth using.
Related Articles (Internal Links)
Other articles related to this topic.
- Remix Complete Guide
- Express.js Complete Guide | Fast Node.js Web Framework
- The Complete Next.js App Router Guide | Server Components, Streaming, Parallel Routes
Keywords Covered in This Article (Related Search Terms)
This article covers React Router, React, Routing, SPA, JavaScript, TypeScript.