React Router v7
React Router는 React 전용 클라이언트 라우팅 라이브러리입니다.
SPA(Single Page Application) 방식에서도 URL 기반 네비게이션을 가능하게 하여 사용자 경험을 향상시킵니다.
기존 버전보다 더 단순해지고, 데이터 중심 구조와 UX 향상을 위한 다양한 기능이 추가되었습니다.
주요 특징
빨라진 라우팅 성능
partial rendering 지원 unnecessary re-render 감소 Vite + React 19 환경과 최적화 궁합
단순해진 API
Routes,Route,Navigate,Outlet중심으로 정리 중첩 라우트가 이전보다 명확해짐데이터 중심 구조 지원 강화
loader / action 등(v7.3+)에서 서버 중심 구조를 도입 서버 액션을 통한 Form 관리 가능
File Router 공식 도입
Next.js App Router와 비슷한 파일 기반 라우팅 자동 코드 스플리팅, Lazy loading
TypeScript 개선
라우트 객체 기반 정의 지원
React Router v7의 핵심 개념 변화
React Router v7은 컴포넌트 라우터가 아니라 데이터 라우터
1
2
3
4
5
6
7
// v6
<Routes>
<Route path="/" element={<Home />} />
</Routes>;
// v7
createBrowserRouter([{ path: "/", element: <Home /> }]);
Router 설정 (routes/index.jsx)
- 객체 기반 라우팅
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import { createBrowserRouter } from "react-router-dom";
import MainLayout from "./layouts";
import Home from "@/pages/Home";
import Login from "@/pages/Login";
import NotFound from "@/pages/NotFound";
export const router = createBrowserRouter([
{
element: <MainLayout />,
children: [
{
path: "/",
element: <Home />,
},
{
path: "/login",
element: <Login />,
},
],
},
{
path: "*",
element: <NotFound />,
},
]);
Layout + Outlet 개념 (routes/layouts.jsx)
- Layout : 공통 UI
- Outlet : 하위 라우트 렌더링 위치
1
2
3
4
5
6
7
8
9
10
11
import { Outlet } from "react-router-dom";
import Header from "@/components/Header";
export default function MainLayout() {
return (
<>
<Header />
<Outlet />
</>
);
}
페이지 이동
1
2
3
4
5
6
// 선언적 이동 : <Link> 사용
<Link to="/about">About</Link>;
// 명령형 이동 : useNavigate() 사용
const navigate = useNavigate();
navigate("/about");
URL 파라미터
- 라우트 객체에서 선언
- loader와 컴포넌트에서 모두 접근 가능
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 라우트 정의
{
path: "/users/:userId",
element: <UserDetail />,
loader: userLoader,
}
// loader에서 접근
// URL 파라미터는 무조건 loader에서 먼저 처리하는 게 실무 표준
export async function userLoader({ params }) {
const { userId } = params;
const res = await fetch(`/api/users/${userId}`);
return res.json();
}
// 컴포넌트에서 접근
import { useLoaderData, useParams } from "react-router-dom";
export default function UserDetail() {
const user = useLoaderData();
const { userId } = useParams();
return (
<div>
<h1>User {userId}</h1>
<p>{user.name}</p>
</div>
);
}
중첩 라우트 (Nested Routes)
- 파라미터는 자동으로 상속
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/dashboard
/dashboard/profile
/dashboard/settings
// 라우트 정의
{
path: "/dashboard",
element: <DashboardLayout />,
loader: dashboardGuard,
children: [
// index route
// /dashboard 진입 시 기본 화면
{
index: true,
element: <DashboardHome />,
},
// /dashboard/profile
{
path: "profile",
element: <Profile />,
loader: profileLoader,
},
// /dashboard/settings
{
path: "settings",
element: <Settings />,
},
],
}
Layout + Outlet
1
2
3
4
5
6
7
8
9
10
11
12
import { Outlet } from "react-router-dom";
export default function DashboardLayout() {
return (
<div>
<Sidebar />
<main>
<Outlet />
</main>
</div>
);
}
errorElement – 에러 처리
- 라우트 단위 에러 처리
1
2
3
4
5
{
path: "/",
element: <Home />,
errorElement: <ErrorPage />,
}
인증 Guard (실무 핵심)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
export async function authLoader() {
const isLoggedIn = false;
if (!isLoggedIn) {
throw redirect("/login");
}
return null;
}
{
element: <MainLayout />,
loader: authLoader,
children: [...],
}
Redirect (리다이렉트)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 컴포넌트 기반
import { Navigate } from "react-router-dom";
return <Navigate to="/login" replace />;
// 라우트 로직 기반 (권장)
import { redirect } from "react-router-dom";
export async function loader() {
const isLoggedIn = false;
if (!isLoggedIn) {
throw redirect("/login");
}
return null;
}
Data Fetch – 라우트 단위 데이터 로딩
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
export async function homeLoader() {
const res = await fetch("/api/home");
return res.json();
}
{
path: "/",
element: <Home />,
loader: homeLoader,
}
// 페이지에서 사용 시
import { useLoaderData } from "react-router-dom";
export default function Home() {
const data = useLoaderData();
return <div>{data.title}</div>;
}
v7에서 loader
Route에 진입할 때 컴포넌트 렌더링 전에 실행되는 비동기 함수로 다양한 역할을 수행합니다.
- 서버 데이터 조회
- 인증 / 권한 체크 (Guard)
- redirect 판단
- 에러 throw
또한,
- 반환 값은
useLoaderData()로 접근 redirect()/throw new Response()가능- URL params, search params 접근 가능
즉, Guard + Redirect + Data Fetch를 하나의 진입 파이프라인에서 처리합니다.
기본 동작 흐름
1
2
3
4
5
6
7
8
URL 접근
↓
해당 route의 loader 실행
↓
(조건 판단)
├─ redirect 발생 → 즉시 이동
├─ error throw → errorElement 렌더
└─ 정상 → element 렌더 + data 전달
action
HTTP의 POST / PUT / PATCH / DELETE에 대응하는 라우트 함수입니다.
기본 동작 흐름
1
2
3
4
5
6
7
8
9
10
11
12
사용자가 <Form method="post"> 제출
↓
해당 route의 action 실행
↓
action 내부에서 서버 API 호출
↓
(조건 판단)
├─ redirect()
├─ JSON 반환
└─ 에러 throw
↓
관련 loader 자동 revalidation