TanStack Router 공식문서 정리 #1 : Route Trees & Nesting, Routing Concepts

ddiae·2024년 7월 24일

TanStack Router

목록 보기
2/3
post-thumbnail

📌 Route Trees & Nesting

다른 라우터처럼 TanStack Router는 중첩된 라우트 트리를 사용하여 URL과 렌더링할 올바른 컴포넌트 트리를 매칭한다.

TanStack Router는 라우트 트리를 구축하기 위해 두 가지 방식을 지원한다.

  • 파일 기반 라우팅
  • 코드 기반 라우팅

두 방법 모두 동일한 기능을 지원하지만 파일 기반 라우팅은 더 적은 코드로 더 나은 결과를 구현할 수 있어 권장되는 방법이다.

Route Trees

중첩 라우팅은 URL을 사용해 중첩된 컴포넌트 트리를 렌더링할 수 있게 해주는 강력한 개념이다.

예를 들어, /blog/posts/123 라는 URL이 주어졌을 때 다음과 같은 계층 구조를 매칭할 수 있다.

  • /blog
    • posts
      • $postId

그리고 다음과 같은 컴포넌트 트리를 렌더링할 수 있다.

<Blog>
  <Posts>
    <Post postId="123" />
  </Posts>
</Blog>

중첩 라우팅을 구성하기 위해 TanStack Router는 라우트 트리라는 라우트 계층 구조를 사용하여 경로를 조직하고 매칭하며, 매칭된 경로를 컴포넌트 트리로 구성한다.

중첩 라우팅 구조는 복잡한 애플리케이션에서 URL 구조와 컴포넌트 트리를 명확하게 유지하는 데 매우 유용하며, 개발자는 URL의 변화에 따라 자연스럽게 컴포넌트 트리를 업데이트 할 수 있다.

대소문자 구분 (Case-Sensitivity)

기본적으로 라우트 경로는 대부분의 웹이 작동하는 방식과 동일하게 대소문자를 구분하지 않는다. 예를 들어 about.tsxABOUT.tsx는 기본적으로 동일 경로로 간주된다.

대소문자를 구분하여 경로를 매칭하고 싶은 경우 라우트의 caseSensitive 옵션을 true로 설정할 수 있다.

import { createRoute } from '@tanstack/react-router'

// 기본적으로 대소문자 구분 없음
export const aboutRoute = createRoute({
  path: 'about',
  component: About,
})

// 대소문자 구분 설정
export const specialRoute = createRoute({
  path: 'SpecialPath',
  component: SpecialComponent,
  caseSensitive: true,
})

출처 : Route Trees & Nesting | TanStack Router React Docs


📌Routing Concepts

The Root Route

루트 라우트는 모든 라우팅 트리의 최상위 라우트로 다른 모든 라우트를 자식으로 챕슐화한다.

No Path
Always Matched
Always Rendered

경로가 없지만(No Path) 다른 라우트와 동일한 기능에 접근할 수 있다, → components, loader, search param validation … etc.

루트 라우트를 생성하기 위해서 createRootRoute() 생성자를 호출하고, 라우트 파일에서 Route 변수로 내보낸다.

import { createRootRoute } from '@tanstack/react-router'

export const Route = createRootRoute()

또한 createRootRouteWithContext<TContext>() 함수를 통해 type-safe 한 방법으로 전체 라우터에 대한 의존성 주입을 할 수 있다.

💡 라우트의 구조
루트 라우트를 제외한 모든 라우트는 FileRoute 클래스를 사용하여 구성된다.
FileRoute 클래스는 파일 기반 라우팅을 사용할 때 타입 안정성을 제공하는 Route 클래스의 wraooer이다.

import { createFileRoute } from '@tanstack/react-router'

export const Route = createFileRoute('/posts')({
  component: PostsComponent,
})

createFileRoute 함수는 파일 라우트의 경로를 문자열로 지정하는 하나의 인자를 받는다.

이 경로는 TanStack Router 플러그인 또는 Router CLI를 통해 자동으로 작성되고 관리된다. 따라서 새로운 라우트를 생성하거나 라우트를 이동하거나, 이름을 변경할 때 경로는 자동으로 업데이트 된다.

Static Routes

정적 라우트는 특정 경로와 정확히 일치하는 라우트로 /about, /settings, /settings/profile, /settings/notifications 경로는 모두 정적 라우트이다. 정적 라우트는 경로와 정확히 일치하여 제공된 컴포넌트를 렌더링한다.

import { createFileRoute } from '@tanstack/react-router'

export const Route = createFileRoute('/about')({
  component: AboutComponent,
})

function AboutComponent() {
  return <div>About</div>
}

Index Routes

인덱스 라우트는 부모 라우트가 정확히 일치하고 자식 라우트가 일치하지 않을 때 타겟이 된다.

import { createFileRoute } from '@tanstack/react-router'

export const Route = createFileRoute('/posts/')({
  component: PostsIndexComponent,
})

function PostsIndexComponent() {
  return <div>Please select a post!</div>
}

위 코드에서 posts.index.tsx 파일은 posts 디렉토리 아래에 위치하여 URL이 /posts와 정확히 일치할 때 매칭된다. 이 경우 PostsIndexComponent가 렌더링된다.

Dynamic Route Segments

경로 세그먼트가 $로 시작하고 레이블이 뒤따르는 경우, 동적 경로 세그먼트가 되어 URL의 해당 부분을 애플리케이션에서 사용할 수 있도록 params객체에 캡쳐한다. 예를 들어 /posts/123 경로는 /posts/$postId라우트와 매칭되며 param 객체는 { postId: '123' }이 된다.

import { createFileRoute } from '@tanstack/react-router'

export const Route = createFileRoute('/posts/$postId')({
  // 로더에서 사용
  loader: ({ params }) => fetchPost(params.postId),
  // Or 컴포넌트에서 사용
  component: PostComponent,
})

function PostComponent() {
  const { postId } = Route.useParams()
  return <div>Post ID: {postId}</div>
}

Splat / Catch-All Routes

splat 라우트는 경로가 $로만 이루어진 라우트로, URL 경로의 남은 부분을 모두 캡쳐하여 params 객체의 _splat 속성에 저장한다. 예를 들어, 경로 트리에 files/$ 스플랫 라우트가 있으면, URL 경로가 /files/documents/hello-world일 때 params 객체는 다음과 같은 값을 갖는다.

{
  '_splat': 'documents/hello-world'
}

Pathless / Layout Routes

경로가 _로 시작하는 파일 라우트는 "경로 없음(Pathless)" 또는 "레이아웃(Layout)" 라우트로 간주된다. 이러한 라우트는 URL에 매칭되지 않지만, 자식 라우트를 추가적인 컴포넌트 및 로직으로 감쌀 때 사용된다.

💡 사용 예시
• 자식 라우트를 레이아웃 컴포넌트로 감싸기
• 자식 라우트를 표시하기 전에 로더 요구 사항 적용
• 자식 라우트에 검색 매개변수 검증 및 제공
• 자식 라우트에 오류 컴포넌트 또는 대기 요소 제공
• 모든 자식 라우트에 공유 컨텍스트 제공

_layout 경로는 URL 경로에 직접 매칭되지 않지만, 자식 경로를 감싸서 공통 레이아웃을 제공하는 데 사용된다. 예를 들어, URL이 /layout-a일 때, 실제로 매칭되는 경로는 /layout-a가 아니라 /layout-a를 감싸는 _layout이다.

import { Outlet, createFileRoute } from '@tanstack/react-router'

// '_layout' 경로를 정의한다. 이 경로는 자식 경로를 감싸는 레이아웃 역할을 한다.
export const Route = createFileRoute('/_layout')({
  component: LayoutComponent,
})

// LayoutComponent는 자식 경로를 감싸는 레이아웃 컴포넌트이다.
function LayoutComponent() {
  return (
    <div>
      <h1>Layout</h1>
      {/* Outlet은 자식 컴포넌트를 렌더링하는 자리 표시자 역할을 한다. */}
      <Outlet />
    </div>
  )
}

위의 설정에 따르면, URL이 /layout-a일 때 _layout 경로가 자식 경로 layout-a를 감싸게 된다. 결과적으로 렌더링되는 컴포넌트 트리는 다음과 같다.

<Layout>
  <LayoutA />
</Layout>

Non-Nested Routes

Non-nested routes는 부모 파일 라우트 세그먼트에 _를 접미사로 붙여서 생성할 수 있다. 이는 특정 라우트가 부모 라우트의 경로를 벗어나 완전히 다른 컴포넌트 트리를 렌더링 할 필요가 있을 때 유용하다.

경로 매칭 중에 _는 무시되므로 /posts/posts_는 동일한 경로로 간주된다. 하지만, 컴포넌트 트리를 구성할 때 _는 중첩되지 않은(non-nested) 라우트를 나타내므로 /posts/posts_는 다른 라우트로 간주된다

/posts/posts_는 동일한 경로이지만, 다른 라우트로 간주된다.
즉, 경로는 똑같이 /posts/… 로 나타나지만 사실상 다른 라우트 트리를 가지고 있는 것이라고 볼 수 있다.

Not-Found Routes

NotFoundRoutes는 특정 조건에서 렌더링되는 특별한 유형의 라우트로 명시적인 경로 트리의 일부는 아니지만, 경로 매칭이 실패했을 때 유용하게 사용 가능하다.

NotFoundRoutes가 렌더링되는 경우

• 가능한 경로 매칭을 초과하는 URL 경로 세그먼트가 있을 때
• 초과된 경로 세그먼트를 캡처할 동작 세그먼트나 스플랫 라우트가 없을 때
• 부모 라우트가 매칭될 때 렌더링할 인덱스 라우트가 없을 떄
• 라우터에 notFountRoute가 제공된 경우

NotFoundRoutes의 특징

  • 경로 없음
  • ID 없음
  • 경로 매개변수 파싱 및 검증 불가

NotFoundRoutes의 기능

  • 컴포넌트 렌더링 : component, pendingComponent, errorComponents를 렌더링
  • 검색 매개변수 검증 및 수신
  • 로더 및 beforeLoad 훅 구성
  • 루트 라우트로부터 데이터와 검색 매개변수 수신

아래 예시는 /posts/about 경로 외의 모든 경로에 대해 NotFoundComponent를 렌더링한다.

//main.tsx
import { StrictMode } from 'react';
import ReactDOM from 'react-dom/client';
import { RouterProvider, createRouter } from '@tanstack/react-router';
import { routeTree } from './routeTree.gen';
import './index.css';
import NotFound from './shared/NotFound';

const router = createRouter({ routeTree, defaultNotFoundComponent: NotFound });

declare module '@tanstack/react-router' {
    interface Register {
        router: typeof router;
    }
}
const rootElement = document.getElementById('root')!;
if (!rootElement.innerHTML) {
    const root = ReactDOM.createRoot(rootElement);
    root.render(
        <StrictMode>
            <RouterProvider router={router} />
        </StrictMode>
    );
}
//NotFound.tsx
export default function NotFound(): JSX.Element {
    return (
        <div className='bg-[red]'>
            <h1 className='text-white'>⚠️404 - Not Found😿⚠️</h1>
        </div>
    );
}

라우트 트리에 NotFoundeRoute를 포함하지 않는다.
라우터 생성 시 defaultNotFoundComponent 옵션에 컴포넌트를 제공하여, 모든 경로에서 작동하도록 설정한다.

출처 : Routing Concepts | TanStack Router React Docs

profile
짱짱

0개의 댓글