React Router v6로 SPA에서 여러 페이지를 구현하는 방법, 동적 라우팅, 중첩 라우팅, useNavigate, useParams를 실전 예제로 배웁니다.
🗺️ 클라이언트 사이드 라우팅이란
SPA에서 URL이 바뀌어도 전체 페이지를 서버에서 다시 받지 않습니다. 자바스크립트가 URL 변경을 감지하고 해당하는 컴포넌트를 렌더링합니다. 이것이 클라이언트 사이드 라우팅(CSR)입니다. React Router v6가 이를 담당합니다.
npm install react-router-dom
⚙️ 기본 설정
애플리케이션 진입점에서 라우터를 설정합니다:
// main.tsx
import { BrowserRouter } from 'react-router-dom'
ReactDOM.createRoot(document.getElementById('root')!).render(
<BrowserRouter>
<App />
</BrowserRouter>
)
// App.tsx — 라우트 정의
import { Routes, Route } from 'react-router-dom'
import HomePage from './pages/HomePage'
import PostListPage from './pages/PostListPage'
import PostDetailPage from './pages/PostDetailPage'
import NotFoundPage from './pages/NotFoundPage'
function App() {
return (
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/posts" element={<PostListPage />} />
<Route path="/posts/:postId" element={<PostDetailPage />} /> {/* 동적 라우팅 */}
<Route path="*" element={<NotFoundPage />} /> {/* 404 */}
</Routes>
)
}
🔗 Link 컴포넌트 — 페이지 이동
일반 <a href> 태그를 쓰면 페이지 전체가 새로고침됩니다. React Router의 <Link>를 사용해야 합니다:
import { Link } from 'react-router-dom'
function Navigation() {
return (
<nav className="flex gap-6">
<Link to="/" className="text-gray-700 hover:text-indigo-600">홈</Link>
<Link to="/posts" className="text-gray-700 hover:text-indigo-600">게시글</Link>
</nav>
)
}
// NavLink: 현재 경로와 일치하면 active 스타일 자동 적용
import { NavLink } from 'react-router-dom'
function Sidebar() {
return (
<nav>
<NavLink
to="/posts"
className={({ isActive }) =>
isActive ? 'text-indigo-600 font-bold' : 'text-gray-600'
}
>
게시글
</NavLink>
</nav>
)
}
🔢 동적 라우팅 — useParams
URL에 :postId처럼 콜론을 붙이면 동적 파라미터입니다. useParams()로 읽습니다:
// PostDetailPage.tsx
import { useParams } from 'react-router-dom'
interface Post { id: number; title: string; body: string; userId: number }
export default function PostDetailPage() {
const { postId } = useParams<{ postId: string }>()
const { data: post, loading, error } = useFetch<Post>(
`https://jsonplaceholder.typicode.com/posts/${postId}`
)
if (loading) return <div>불러오는 중...</div>
if (error) return <div>오류: {error}</div>
if (!post) return null
return (
<article className="max-w-2xl mx-auto p-6">
<h1 className="text-2xl font-bold mb-4">{post.title}</h1>
<p className="text-gray-600 leading-relaxed">{post.body}</p>
</article>
)
}
🧭 프로그래밍 방식 이동 — useNavigate
버튼 클릭 후 다른 페이지로 이동하거나, 로그인 후 리다이렉트할 때 사용합니다:
import { useNavigate } from 'react-router-dom'
function LoginForm() {
const navigate = useNavigate()
async function handleLogin() {
// 로그인 로직...
navigate('/') // 홈으로 이동
navigate(-1) // 뒤로 가기
navigate('/dashboard', { replace: true }) // 히스토리 교체 (뒤로 가기 불가)
}
return <form onSubmit={handleLogin}>...</form>
}
📂 중첩 라우팅 — Outlet
대시보드처럼 공통 레이아웃 안에서 하위 페이지가 바뀌는 구조에 사용합니다:
// App.tsx
<Routes>
<Route path="/admin" element={<AdminLayout />}>
<Route index element={<AdminDashboard />} /> {/* /admin */}
<Route path="users" element={<AdminUsers />} /> {/* /admin/users */}
<Route path="posts" element={<AdminPosts />} /> {/* /admin/posts */}
</Route>
</Routes>
// AdminLayout.tsx — Outlet이 하위 페이지를 렌더링하는 자리
import { Outlet, Link } from 'react-router-dom'
function AdminLayout() {
return (
<div className="flex">
<aside className="w-48 bg-gray-800 text-white p-4">
<Link to="/admin/users" className="block py-2">사용자</Link>
<Link to="/admin/posts" className="block py-2">게시글</Link>
</aside>
<main className="flex-1 p-6">
<Outlet /> {/* 하위 라우트 컴포넌트가 여기 렌더링 */}
</main>
</div>
)
}
✅ 정리
BrowserRouter로 앱 전체를 감싸고,Routes/Route로 경로를 정의합니다.- 페이지 이동은
<Link to="/path">. 코드에서 이동은useNavigate(). :파라미터로 동적 라우팅,useParams()로 읽습니다.- 중첩 라우팅: 부모 레이아웃에
<Outlet />을 배치합니다.
관련 주제
- 완료 토글 기능
- 삭제 기능
- 필터링 구현
- 상태 구조 리팩토링
- 개발·프로그래밍
- 개발·프로그래밍 강의
- 리액트 입문 — 컴포넌트로 만드는 웹
- 무료강의
- 무료 온라인 강의
- NUGUNA
- 누구나
댓글
0/1000
불러오는 중...
