컴포넌트가 렌더링된 후 데이터를 가져오는 기존 방식(Waterfall)을 탈피하여, 페이지 이동과 동시에 데이터를 준비하는 효율적인 데이터 패칭 기법임
키워드: createBrowserRouter, loader, useLoaderData, Outlet, NavLink (end)
리액트 라우터 6.4 버전부터는 객체 기반의 라우터 설정을 통해 복잡한 계층 구조를 직관적으로 관리할 수 있습니다.
❖ 구조적 특징:
RootLayout: 전체 앱의 공통 뼈대 (네비게이션 등).EventsRootLayout: /events 하위 페이지들의 공통 레이아웃.Outlet: 부모 라우트 컴포넌트 내에서 자식 라우트 컴포넌트가 렌더링될 위치를 지정함.NavLink (end): 경로가 정확히 일치할 때만 활성 상태(active)를 표시하도록 제한함.기존의 useEffect 방식은 컴포넌트가 화면에 나타난 뒤에야 데이터를 가져왔지만, loader는 페이지에 발을 들이기 전에 미리 장을 봐오는 것과 같습니다.
| 방식 | 흐름 (Process) | 사용자 경험 (UX) |
|---|---|---|
| 기존 (useEffect) | 컴포넌트 렌더링 → fetch 실행 → 상태 업데이트 → 재렌더링 | 빈 화면이나 로딩 스피너를 먼저 보게 됨 |
| 혁신 (loader) | 데이터 로딩 완료(await) → 완성된 데이터와 함께 컴포넌트 등장 | 데이터가 채워진 완성된 페이지를 즉시 보게 됨 |
loader는 라우트 설정 단계에서 함수를 연결하여, 해당 경로로 이동하기 직전에 데이터를 미리 가져오는 '사전 준비 요원'입니다.
{
path: 'events',
element: <EventsRootLayout />,
children: [
{
index: true,
element: <EventsPage />,
// 페이지 이동 전 실행되는 사전 로딩 함수
loader: async () => {
const response = await fetch('http://localhost:8080/events');
if (!response.ok) {
// 에러 처리 로직
} else {
const resData = await response.json();
return resData.events; // 리턴된 데이터는 컴포넌트에서 useLoaderData로 사용 가능
}
},
},
{ path: ':eventId', element: <EventDetailPage /> },
],
}
- 사용자 클릭: 사용자가
/events링크를 클릭함.- Loader 가동: 리액트 라우터가 해당 경로의
loader함수를 감지하고 데이터를 가져오기 시작함.- 컴포넌트 렌더링: 데이터 로딩이 끝날 때까지 이동을 잠시 유보했다가, 데이터가 준비되면
EventsPage를 화면에 뿌림.- 데이터 사용: 컴포넌트 내부에서
useLoaderData()훅을 통해useState없이도 데이터를 바로 사용함.
중첩된 라우트 구조에서 레이아웃 컴포넌트는 UI의 일관성을 유지하는 핵심 역할을 합니다.
❖ 레이아웃 관리:
EventsRootLayout 내부에 <EventsNavigation />을 배치하고 그 아래에 <Outlet />을 둡니다./events, /events/new, /events/1 등 어떤 하위 페이지로 가더라도 서브 네비게이션은 고정된 채 알맹이(Outlet)만 바뀌게 됩니다.