React Router v7 - (2) API Components

장유진·2026년 2월 22일

React Router v7

목록 보기
2/5
post-thumbnail

Components에서 공통으로 사용되는 props

  • discover: lazy route discovery 동작 정의
    • render (default): 폼 렌더링 시 route 미리 탐색
    • none: 미리 탐색하지 않고 폼 제출 시 route 탐색
  • preventToScrollReset: <ScrollRestoration> 컴포넌트를 사용했을 때 스크롤이 위로 초기화되는 것을 막는다.
  • relative: action의 경로를 route 기준으로 계산할지, URL 경로 기준으로 계산할지 결정한다.
    • route (default): route 계층 구조를 기반으로 계산하여 route("posts/:id")에서 ..로 이동할 경우 /로 이동하게 된다. route의 정의 자체가 posts/:id이기 때문!
    • path: URL pathname을 기반으로 계산하여 route("posts/:id")에서 ..로 이동할 경우 /post로 이동하게 된다. URL 세그먼트 하나만 제거하면 되기 때문!
  • reloadDocument: SPA의 동작을 무시하여 clide side 라우팅을 하지 않고 강제로 전체 페이지를 새로고침한다.
  • replace: 브라우저 히스토리 스택에 state를 새로 쌓지 않고 현재 state를 교체한다. 뒤로 가기를 눌렀을 때 이전 폼 페이지로 돌아가지 않는다.
  • state: 히스토리 스텍에 쌓일 state를 정의한다.
  • viewTransition: View Transition을 활성화한다.
  • unstable_defaultShouldRevalidate: 폼 제출 이후 revalidation 동작을 수정한다. 현재 라우트에 shouldRevalidate 함수가 없으면 이 값을 사용하고 있으면 shouldRevalidate 함수에 전달된다.

1. Await

Await 컴포넌트는 Promise 값을 사용하여 렌더링하며 에러도 함께 처리할 수 있다.

AwaitReact.Suspense 내부에서 사용되어야 한다.

<React.Suspense fallback={<ReviewsSkeleton />}>
  <Await
    resolve={reviews}
    errorElement={<div>Could not load reviews 😬</div>}
    children={(resolvedReviews) => (
      <Reviews items={resolvedReviews} />
    )}
  />
</React.Suspense>

// 또는

<React.Suspense fallback={<ReviewsSkeleton />}>
  <Await
    resolve={reviews}
    errorElement={<div>Could not load reviews 😬</div>}
  >
    {(resolvedReviews) => <Reviews items={resolvedReviews} />}
  </Await>
</React.Suspense>

props

  • children: resolve된 값을 받아 렌더링할 컴포넌트. children 내부에서는 useAsyncValue 훅을 사용하여 resolve된 값에 접근할 수 있다.
  • errorElement: Promise가 reject될 경우 children 대신 렌더링할 컴포넌트. errorElement 내부에서는 useAsyncError 훅을 사용하여 error 객체에 접근할 수 있다.
  • resolve: Promise 객체. 일반적으로 loader에서 리턴한 값을 사용한다.

2. Form

React Router의 Form은 HTML의 <form>을 확장한 컴포넌트로, fetch 기반 폼 제출, useNavigation과 연동, 자동 revalidation과 같은 기능을 제공한다.

HTML form API를 사용하므로 JavaScript 로드 전에는 기본 HTML form처럼 동작이 가능하고, JavaScript 로드 후에는 React Router가 더 좋은 사용자 경험이 가능하도록 처리할 수 있게 된다. (이것이 바로 Progressive enhancement!)

Form은 URL 변경이나 브라우저 히스토리에 기록이 남아야 하는 경우에 적합하고, 브라우저 히스토리 스택에 변경이 없게 하려면 <fetcher.form>을 사용해야 한다.

❓ Progressive enhancement란?

가장 낮은 환경에서도 핵심 기능이 작동하게 만들고, 환경이 좋아질수록 기능을 덧붙여 사용자 경험을 향상시키는 전략

import { Form } from "react-router";

function NewEvent() {
  return (
    <Form action="/events" method="post">
      <input name="title" type="text" />
      <input name="description" type="text" />
    </Form>
  );
}

props

  • action: form 데이터를 제출할 URL. actionundefined일 경우 가장 가까운 route의 경로를 기본값으로 사용한다.
  • encType: 인코딩 타입 정의
  • fetcherKey: navigate={false} 옵션을 사용할 경우 다른 컴포넌트에서 useFetcher에 키를 전달하여 상태를 공유할 수 있도록 함
  • method: 폼 제출 시 사용할 HTTP 메서드. Progressive enhancement를 사용하고 싶다면 get이랑 post만 사용하는 것이 좋다.
  • navigate: 이 옵션이 false일 경우 navigation을 하지 않고 fetcher를 통해 폼 제출을 처리한다.
  • onSubmit: 폼 제출 시 실행할 콜백함수. onSubmit 내부에서 e.preventDefault()를 사용할 경우 아무것도 동작하지 않는다.
  • discover
  • preventToScrollReset
  • relative
  • reloadDocument:
  • replace.
  • state
  • viewTransition
  • unstable_defaultShouldRevalidate

❓ Lazy route discovery란?

앱의 모든 경로(Route) 정보를 처음부터 한꺼번에 다 불러오는 대신, 사용자가 이동하는 흐름에 맞춰 필요한 시점에 경로 메타데이터를 점진적으로 불러오는 성능 최적화 기술이다. 현재 화면에 보이는 모든 <Link><NavLink>를 미리 감지하고 해당 라우트의 정보를 미리 요청한다.
참고: https://reactrouter.com/explanation/lazy-route-discovery

❓ View Transition이란?

View Transition API는 웹 페이지의 상태가 바뀔 때(예: 다른 페이지로 이동하거나 DOM 요소가 추가/삭제될 때) 부드러운 애니메이션 효과를 아주 쉽게 구현할 수 있도록 도와주는 최신 브라우저 API이다.
참고: https://developer.mozilla.org/en-US/docs/Web/API/View_Transition_API

점진적 향상(Progressive enhancement)된 <a href> 태그 wrapper이다.

import { Link } from "react-router";

<Link to="/dashboard">Dashboard</Link>;

<Link
  to={{
    pathname: "/some/path",
    search: "?query=string",
    hash: "#hash",
  }}
/>;

props

  • to: 이동할 경로. string 타입이거나 Partial<Path> 타입
  • prefetch: 이동할 라우트의 데이터와 모듈을 prefetch할 지 동작 정의
    • none (default): 아무것도 하지 않음
    • intent: hover나 focus 시 prefetch
    • render: <Link> 컴포넌트 렌더링 시 prefetch
    • viewport <Link> 컴포넌트가 화면에 보이면 prefetch
  • discover
  • preventToScrollReset
  • relative
  • reloadDocument
  • replace
  • state
  • viewTransition
  • unstable_defaultShouldRevalidate

route module에서 export한 link 배열을 사용하여 <link> 태그들을 렌더링하는 컴포넌트

import { Links } from "react-router";

export default function Root() {
  return (
    <html>
      <head>
        <Links />
      </head>
      <body></body>
    </html>
  );
}

props

  • nonce: <link>에 전달할 nonce 속성
  • crossOrigin: <link>에 전달할 crossOrigin 속성

5. Meta

route module에서 export한 meta 배열을 사용하여 <meta> 태그들을 렌더링하는 컴포넌트

import { Meta } from "react-router";

export default function Root() {
  return (
    <html>
      <head>
        <Meta />
      </head>
    </html>
  );
}

active 상태와 pending 상태 처리를 추가한 <Link> 컴포넌트 wrapper로, 아래와 같은 기능을 제공한다.

  • active 상태와 pending 상태에 따라 자동으로 class 적용 (단, pending은 Framework 또는 Data 모드에서만 사용 가능)
  • active한 링크에 자동으로 aria-current=”page” 속성 추가
  • className, style, children에 상태와 관련된 render props 지원
<NavLink to="/message">Messages</NavLink>

<NavLink
  to="/messages"
  className={({ isActive, isPending }) =>
    isPending ? "pending" : isActive ? "active" : ""
  }
>
  Messages
</NavLink>

props

  • caseSensitive: 대소문자 구분 여부
  • children: NavLink 내부에서 상태에 따라 렌더링할 컴포넌트
  • className: 상태에 따라 적용될 class 커스텀
  • style: 상태에 따라 적용될 스타일
  • end: 기본적으로는 URL path가 부분 매칭되어도 active 상태지만, end를 사용하면 정확히 끝까지 매칭해야 active 상태가 됨
  • to: 이동할 경로. string 타입이거나 Partial<Path> 타입
  • prefetch: 이동할 라우트의 데이터와 모듈을 prefetch할 지 동작 정의
    • none (default): 아무것도 하지 않음
    • intent: hover나 focus 시 prefetch
    • render: <Link> 컴포넌트 렌더링 시 prefetch
    • viewport <Link> 컴포넌트가 화면에 보이면 prefetch
  • discover
  • preventToScrollReset
  • relative
  • reloadDocument
  • replace
  • state
  • viewTransition

7. Navigate

hook을 사용할 수 없는 React의 클래스형 컴포넌트에서 useNavigate 대신 사용할 컴포넌트

<Navigate to="/tasks" />

props

  • to: 이동할 경로. string 타입이거나 Partial<Path> 타입
  • relative
  • replace
  • state

8. Outlet

부모 라우트 안에서 자식 라우트를 렌더링하는 컴포넌트. 자식 라우트가 없다면 아무것도 렌더링하지 않는다.

import { Outlet } from "react-router";

export default function SomeParent() {
  return (
    <div>
      <h1>Parent Content</h1>
      <Outlet />
    </div>
  );
}

props

  • context: 부모에서 자식으로 전달하는 context 데이터. 자식 내부에서는 useOutletContext 훅을 사용하여 접근할 수 있다.

특정 페이지의 모듈과 데이터를 미리 가져와서 바로 이동할 수 있게 하기 위해 <linke rel=prefetch|modulepreload> 태그를 렌더링하는 컴포넌트. prefetch 옵션을 사용하는 <Link>가 내부적으로 이 컴포넌트를 사용하지만, 링크가 없어도 특정 조건에서 페이지를 미리 로드하고 싶을 때 사용할 수 있다.

import { PrefetchPageLinks } from "react-router";

<PrefetchPageLinks page="/absolute/path" />

props

  • page: prefetch할 대상 페이지의 절대경로
  • linkProps: 생성되는 <link> 태그에 추가할 속성

10. Route

현재 경로와 path가 매치되면 렌더링할 컴포넌트를 설정하는 컴포넌트로, Routes 컴포넌트 내부에서만 사용할 수 있다.

// Usually used in a declarative router
function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route index element={<StepOne />} />
        <Route path="step-2" element={<StepTwo />} />
        <Route path="step-3" element={<StepThree />} />
      </Routes>
   </BrowserRouter>
  );
}

// But can be used with a data router as well if you prefer the JSX notation
const routes = createRoutesFromElements(
  <>
    <Route index loader={step1Loader} Component={StepOne} />
    <Route path="step-2" loader={step2Loader} Component={StepTwo} />
    <Route path="step-3" loader={step3Loader} Component={StepThree} />
  </>
);

const router = createBrowserRouter(routes);

function App() {
  return <RouterProvider router={router} />;
}

props

  • action
  • caseSensitive
  • Component: 경로가 매칭될경우 렌더링할 React Component. element와 상호 배타적
  • children: 자식 Route 컴포넌트
  • element: 경로가 매칭될 경우 렌더링할 React Element. Component 와 상호 배타적
  • ErrorBoundary: 에러가 발생할 경우 렌더링할 React Component. errorElement와 상호 배타적
  • errorElement: 에러가 발생할 경우 렌더링할 React Element. ErrorBoundary와 상호 배타적
  • handle: 라우트에 임의의 데이터를 전달할 수 있다. 라우트 내부에서 useMatches 훅으로 접근 가능하다.
  • HydrateFallback: 로딩 중 렌더링할 React Component. hydrateFallbackElement와 상호 배타적
  • hydreateFallbackElement: 로딩 중 렌더링할 React Element. HydrateFallback 과 상호 배타적
  • id: DataRouter에서 사용하는 유니크한 라우트 식별값
  • index: 부모 경로의 기본 자식이 된다. path와 함께 사용하지 않는다.
  • lazy: route object를 반환하는 함수로, code-splitting을 위해 사용한다. Componentelement와 함께 사용하지 않는다.
  • loader
  • path: 매칭할 경로 패턴. 생략하면 layout route가 된다.
  • shouldRevalidate: 해당 라우트에 적용할 shouldRevalidate 함수

❓ Element 방식과 Component 방식의 차이는?

Element 방식은 이미 생성된 React Element를 넘기는 것이고, Component 방식은 React Component 함수 자체를 넘기는 것이다. 따라서 Element 방식은 <Route element={<Home />} /> 로 사용하고, App 렌더링 시점에 이미 <Home />이 생성되어 있다. 반면에 Component 방식은 <Route Component={Home} />로 사용하고, 라우트가 실제로 매칭될 때 생성된다.

❓ 상호 배타적(Mutually Exclusive)이 무슨 뜻이지?

서로 동시에 존재할 수 없는 관계라는 뜻이다. 즉, 하나를 선택하면 다른 하나는 사용할 수 없다.

11. Routes

현재 location에 가장 잘 맞는 <Route>를 찾아서 하나의 branch를 렌더링한다.

import { Route, Routes } from "react-router";

<Routes>
  <Route index element={<StepOne />} />
  <Route path="step-2" element={<StepTwo />} />
  <Route path="step-3" element={<StepThree />} />
</Routes>

props

  • children: 중첩된 Route들
  • location: 매칭할 location. 기본값은 window.location 기반의 현재 URL이다.

❓ branch란?

중첩 라우트일 때 하나의 트리 경로를 말한다. 렌더링 시 Outlet을 통해 단계적으로 렌더링된다.

12. Scripts

client runtime을 렌더링하는 컴포넌트. <body> 태그 안에 위치해야 한다.

서버 렌더링 중에는 <Scripts /> 컴포넌트가 생략되어 자바스크립트 없이 HTML과 브라우저 동작에만 의존하여 동작하게 된다.

즉, <Scripts /> 는 서버에서 HTML을 먼저 렌더링한 후 브라우저에서 React가 hydrate 되도록 JS를 로드해주는 역할을 한다. <Scripts /> 가 있어야 loader 데이터 hydration, client navigation, fetcher, action 처리 등이 가능해진다.

import { Scripts } from "react-router";

export default function Root() {
  return (
    <html>
      <head />
      <body>
        <Scripts />
      </body>
    </html>
  );
}

props

  • scriptProps: <script> 태그에 넣을 속성들

❓ client runtime 이란?

클라이언트에서 실행될 자바스크립트 번들로, Hydration을 통해 브라우저에서 리액트의 로직과 라우팅 기능이 실제로 작동할 수 있게 해준다.

13. ScrollRestoration

브라우저의 스크롤 복원 동작을 흉내내서 구현하는 컴포넌트이다. scroll flashing을 방지하는 inline <script> 태그를 렌더링한다.

앱에서 딱 한 번만 렌더링 해야 하며, <Scripts /> 컴포넌트 바로 위에 위치해야 한다.

inline script를 생성하기 때문에 CSP가 strict하면 차단될 수 있는데, 그럴 경우 nonce={cspNonce} prop을 사용한다.

import { ScrollRestoration } from "react-router";

export default function Root() {
  return (
    <html>
      <body>
        <ScrollRestoration />
        <Scripts />
      </body>
    </html>
  );
}

props

  • getKey: 스크롤을 저장할 때 사용할 키. 기본값은 location.key이며, 커스텀한 스크롤 복구 로직을 구현할 때 사용하면 좋다.
    • location.key: 히스토리 단위로 복구
    • location.pathname: 동일한 path에 접근할 경우 항상 이전 스크롤 위치 복구
  • nonce: <script> 태그에 전달될 nonce 속성
  • storageKey: session storage에 스크롤 위치를 저장할 때 사용하는 키. 기본값은 "react-router-scroll-positions”이다.

❓ scroll flashing이란?

화면이 잠깐 잘못된 스크롤 위치를 보여줬다가 다시 올바른 위치로 이동하는 현상

❓ nonce란?

한 번만 사용하는 임의의 보안 토큰 (number used once)으로, 브라우저의 CSP 환경에서 특정 <script><style> 태그만 실행을 허용하기 위해 사용한다.

❓ CSP(Content Security Policy)란?

웹 보안을 위한 브라우저 보안 정책 시스템으로, 어디에서 온 리소스만 실행해도 되는지를 명확하게 지시한다. 보통 XSS 공격 방지, 악성 스크립트 실행 차단, 외부 리소스 오용 방지를 위해 사용한다. 활성화하기 위해서는 HTTP 응답 헤더로 Content-Security-Policy를 설정하면 된다.

profile
프론트엔드 개발자

0개의 댓글