React Router v7 — React 19 대비와 타입 안전성 강화 특징 정리

React 생태계가 React 19로 넘어가며 렌더링·데이터·번들 전략이 바뀌고 있습니다. 그 사이에서 React Router v7(RRv7) 은 “기존 v6 앱을 최대한 건드리지 않으면서” SSR·프리렌더·스트리밍을 단계적으로 받아들이게 해 주는 브리지이자, 라우트 모듈 기반의 typegen(자동 타입 생성) 으로 1급 타입 안전성을 제공하는 라우팅 표준입니다. 이 글은 2025년 현재 관점에서 RRv7의 핵심을 업그레이드 경로, React 19 대비, 타입 안전성, 미들웨어, 데이터/에러 모델 중심으로 정리합니다.

목차


1) 한눈에 보는 핵심 요약 (TL;DR)

  • Non‑breaking 업그레이드: v6 → v7은 비파괴적입니다. v6에서 미래 플래그를 적용해 왔다면 “사실상 그대로” 올라탈 수 있습니다.
  • React 19 브리지: 번들링·SSR·프리렌더·스트리밍이 React 18→19 전환을 점진적으로 잇도록 설계되어 있습니다.
  • Typegen(1급 타입): 라우트마다 생성되는 +typesparams/loader/action/컴포넌트 props를 정적으로 보장합니다.
  • 정리된 데이터 유틸: v7에서 json/defer는 제거되었고, 상태코드·헤더가 필요할 땐 data() 로 표준화합니다.

2) React 19 대비 관점에서 본 RRv7

React 19는 스트리밍 SSR, 프리렌더, 서버 중심 데이터 흐름을 전진시킵니다. RRv7은 여기에 맞춰 세 가지 모드(Declarative / Data / Framework) 를 제공하고, 앱이 필요한 범위만큼 기능을 선택 도입하도록 돕습니다.

  • 프리렌더 & SSR 토글: react-router.config.tsprerenderssr 설정으로 정적 생성(SSG)런타임 SSR을 라우트 집합 단위로 병행할 수 있습니다.
  • 스트리밍(Suspense): 로더/액션이 Promise를 반환하면 서버·클라이언트 모두에서 스트리밍 렌더를 활용해 초기 표시를 앞당길 수 있습니다.
  • 다양한 런타임: Cloudflare·Express 등 공식 어댑터가 있어서, 동일한 라우트 계약을 유지한 채 배포 대상을 바꿀 수 있습니다.
  • 최소 버전: RRv7은 Node 20, React 18 이상을 요구합니다(React 19 사용은 선택).

아래 다이어그램은 v6 앱 → v7로 전환하면서 SSR/SSG/스트리밍/Typegen/미들웨어필요한 만큼만 채택하는 흐름을 요약한 것입니다.

flowchart LR
  v6[RR v6 앱] -->|non-breaking| v7[RR v7]
  v7 --> SSR[서버 렌더링(SSR)]
  v7 --> Prerender[프리렌더(SSG)]
  v7 --> Streaming[스트리밍/Suspense]
  v7 --> Typegen[Typegen 기반 타입 안전]
  v7 --> Middleware[미들웨어/컨텍스트]
  SSR --> R19[React 19]
  Prerender --> R19
  Streaming --> R19

덧: v7에서는 패키지 구성이 react-router 단일 패키지로 수렴합니다. 기존 react-router-dom은 점진 업그레이드를 돕기 위한 재노출 래퍼에 가깝습니다.


3) 타입 안전성: 무엇이 ‘강화’됐나

RRv7의 타입 안전성은 자동 타입 생성(typegen) 이 핵심입니다. 개발 서버·CI에서 react-router typegen을 실행하면 프로젝트 루트의 .react-router/types/ 아래에 라우트별 +types 선언이 생성됩니다. 이 타입들은 TS 설정(rootDirs, types)을 통해 소스 옆에 붙은 것처럼 노출되어, 컴포넌트/로더/액션에서 강타입 추론을 제공합니다.

  • 생성 항목 예: LoaderArgs, ClientLoaderArgs, ActionArgs, ClientActionArgs, HydrateFallbackProps, ComponentProps, ErrorBoundaryProps 등.
  • 컨텍스트 타입 등록: 서버 어댑터의 getLoadContext()로 주입되는 값을 AppLoadContext 선언 병합으로 전역 등록하면, 로더/액션에서 안전하게 사용됩니다.

짧은 예시 (typegen 기반)

// app/routes/products.$id.tsx
import type { Route } from "./+types/products.$id";
 
export async function loader({ params }: Route.LoaderArgs) {
  const product = await fetchProduct(params.id);
  if (!product) throw data("Not found", { status: 404 });
  return { product };
}
 
export default function Page({ loaderData }: Route.ComponentProps) {
  return <div>{loaderData.product.name}</div>;
}

포인트: 코드엔 타입 주석이 거의 없지만, Route.* 네임스페이스가 자동 생성되어 런타임 오류를 컴파일 타임에 선제 차단합니다.


4) 데이터·에러·리다이렉트 모델

RRv7은 로더/액션 → 컴포넌트의 데이터 계약을 중심으로, 에러 경계 + 리다이렉트 유틸단일 모델로 엮습니다.

  • 에러 경계: 로더/액션/컴포넌트 어디서든 오류가 나면 가장 가까운 ErrorBoundary 가 렌더됩니다. 경계 안에선 useRouteError()isRouteErrorResponse()로 상황을 구분합니다.
  • 의도적 오류/404: throw data() 혹은 throw new Response()상태코드와 메시지를 명시해 전달합니다.
  • 리다이렉트: return 또는 throw 방식 모두 redirect() 를 사용할 수 있어 PRG(Post/Redirect/Get) 패턴을 단순화합니다.
  • 스트리밍 정합성: defer()는 v7에서 제거되었고, 로더/액션에서 Promise를 직접 반환하는 스트리밍 모델로 단순화됐습니다.

5) 미들웨어 & 컨텍스트(요약 포커스)

미들웨어는 라우트 계층에서 부모→자식으로 “내려가며” 전처리, 응답 생성 뒤 자식→부모로 “올라오며” 후처리하는 중첩 체인입니다. 인증·로깅·A/B 플래그 등 정책 주입을 한 곳에서 일관 적용할 수 있습니다. 프레임워크 모드·데이터 모드 모두 지원되며, 최근 릴리스에서는 API 일관성·안정화 작업이 빠르게 진행되고 있습니다.

실무 팁: 팀 차원에서 컨텍스트 스키마(누가 무엇을 넣는가) 를 문서화하고, 공통 미들웨어를 경로 범위(전역/섹션/개별) 별로 모듈화하면 마이그레이션 비용을 크게 줄일 수 있습니다.


6) 실무 판단 체크리스트(정보형)

이득

  • QA/복구 비용↓: 에러 경계·리다이렉트·재검증 규약이 표준화되어 문제 발생 시 경로가 명확합니다.
  • 점진 도입: v6 코드를 크게 바꾸지 않고 라우트 단위로 SSR/SSG/스트리밍을 실험·확장할 수 있습니다.
  • 패키지 단순화: 신규 프로젝트는 react-router 단일 패키지로 시작해 복잡도를 줄일 수 있습니다.

주의

  • 패턴 혼재 방지: v6 잔존 코드와 v7 기능을 섞을 땐 미들웨어 적용 범위·컨텍스트 타입 등록 규칙을 먼저 합의하세요.
  • 유틸 변경: json()/defer() 제거에 따라 data() + 원시 객체 반환으로 치환하되, 상태코드/헤더 누락에 주의하세요.
  • 최소 요구 버전: Node 20/React 18 이상 환경을 먼저 확보하세요.

7) 짧은 FAQ (완전 정보 전달형)

  • Q. v6에서 당장 올라가야 하나? A. 아님. v7은 비파괴 업그레이드라 시한은 없습니다. 다만 React 19 기능을 점진 도입하려면 v7 채택이 유리합니다.

  • Q. 타입 안전성은 꼭 typegen을 써야 하나? A. 권장. 라우트별 자동 생성 타입이 useLoaderData·action·경계까지 자연스럽게 추론 전파되어 실수를 줄여 줍니다.

  • Q. react-router-dom은 어떻게 되나? **A. v7에선 react-router수렴했습니다. 기존 앱에선 react-router-dom재노출 패키지로 업그레이드 전환을 돕고, 새 앱은 처음부터 react-router만 쓰는 편이 단순합니다.


참고 링크