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:
- Build with [Next.js](/en/blog/nextjs-15-complete-guide/
- Try [Remix](/en/blog/remix-complete-guide/
- Learn [React 18](/en/blog/react-18-deep-dive/
Resources:
자주 묻는 질문 (FAQ)
Q. 이 내용을 실무에서 언제 쓰나요?
A. Complete React Router guide for SPAs. Learn routing, nested routes, loaders, actions, navigation, and building multi-pag… 실무에서는 위 본문의 예제와 선택 가이드를 참고해 적용하면 됩니다.
Q. 선행으로 읽으면 좋은 글은?
A. 각 글 하단의 이전 글 또는 관련 글 링크를 따라가면 순서대로 배울 수 있습니다. C++ 시리즈 목차에서 전체 흐름을 확인할 수 있습니다.
Q. 더 깊이 공부하려면?
A. cppreference와 해당 라이브러리 공식 문서를 참고하세요. 글 말미의 참고 자료 링크도 활용하면 좋습니다.
같이 보면 좋은 글 (내부 링크)
이 주제와 연결되는 다른 글입니다.
- [Remix Complete Guide](/en/blog/remix-complete-guide/
- [Express.js Complete Guide | Fast Node.js Web Framework](/en/blog/express-complete-guide/
- The Complete Next.js App Router Guide | Server Components, Streaming, Parallel Routes
이 글에서 다루는 키워드 (관련 검색어)
React Router, React, Routing, SPA, JavaScript, TypeScript 등으로 검색하시면 이 글이 도움이 됩니다.