React Router 설치
npm install react-router-dom
기본 라우팅 설정
// src/App.tsx
import { BrowserRouter, Routes, Route, Navigate } from "react-router-dom";
import HomePage from "./pages/HomePage";
import UserListPage from "./pages/UserListPage";
import UserDetailPage from "./pages/UserDetailPage";
import NotFoundPage from "./pages/NotFoundPage";
import Layout from "./components/Layout";
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<HomePage />} />
<Route path="users" element={<UserListPage />} />
<Route path="users/:id" element={<UserDetailPage />} />
<Route path="*" element={<NotFoundPage />} />
</Route>
</Routes>
</BrowserRouter>
);
}
Layout과 Outlet
// src/components/Layout.tsx
import { Outlet, NavLink } from "react-router-dom";
function Layout() {
return (
<div>
<nav>
{/* NavLink: 활성 경로에 active 클래스 자동 추가 */}
<NavLink to="/" end>홈</NavLink>
<NavLink to="/users">사용자</NavLink>
</nav>
<main>
{/* 자식 라우트가 여기에 렌더링 */}
<Outlet />
</main>
</div>
);
}
동적 라우트
import { useParams } from "react-router-dom";
function UserDetailPage() {
const { id } = useParams<{ id: string }>();
const { data: user, loading } = useFetch<User>(`/api/users/${id}`);
if (loading) return <Spinner />;
return <div>{user?.name}</div>;
}
쿼리 파라미터
import { useSearchParams } from "react-router-dom";
function UserListPage() {
const [searchParams, setSearchParams] = useSearchParams();
const page = Number(searchParams.get("page") ?? "1");
const query = searchParams.get("q") ?? "";
function handleSearch(newQuery: string) {
setSearchParams({ q: newQuery, page: "1" });
}
function goToPage(newPage: number) {
setSearchParams({ q: query, page: String(newPage) });
}
return (
<div>
<input value={query} onChange={e => handleSearch(e.target.value)} />
{/* URL: /users?q=철수&page=2 */}
</div>
);
}
프로그래밍 방식 이동
import { useNavigate } from "react-router-dom";
function LoginForm() {
const navigate = useNavigate();
const { login } = useAuth();
async function handleSubmit(e: FormEvent) {
e.preventDefault();
await login(email, password);
navigate("/dashboard"); // 이동
// navigate(-1); // 뒤로 가기
// navigate("/login", { replace: true }); // 히스토리 교체
}
}
라우트 보호 (Protected Routes)
function ProtectedRoute({ children }: { children: ReactNode }) {
const { user } = useAuth();
const location = useLocation();
if (!user) {
// 로그인 후 원래 가려던 곳으로 돌아오게 state 전달
return <Navigate to="/login" state={{ from: location }} replace />;
}
return <>{children}</>;
}
// App.tsx에서
<Route path="dashboard" element={
<ProtectedRoute>
<DashboardPage />
</ProtectedRoute>
} />
Link vs NavLink
import { Link, NavLink } from "react-router-dom";
// Link: 단순 이동
<Link to="/about">소개</Link>
// NavLink: 현재 경로와 일치 여부 스타일 적용
<NavLink
to="/users"
className={({ isActive }) => isActive ? "active" : ""}
>
사용자
</NavLink>
정리
| Hook/컴포넌트 | 역할 |
|---|---|
BrowserRouter | 라우터 제공자 |
Routes, Route | 라우트 정의 |
Outlet | 자식 라우트 렌더링 위치 |
Link, NavLink | 페이지 이동 링크 |
useParams | URL 동적 파라미터 |
useSearchParams | 쿼리 파라미터 |
useNavigate | 프로그래밍 이동 |
Navigate | 리다이렉트 |
다음 편에서는 React 실전 프로젝트 — 지금까지 배운 모든 내용을 활용한 투두 앱을 만듭니다.