Tanstack Route 기본 사용법 및 가이드 (File-based Routing)

React Router를 대체할 수 있는 File-based Routing 방식인 Tanstack Route의 기본 사용법과 가이드를 알아봅니다.


소개

Tanstack Route는 React Router를 대체할 수 있는 라이브러리입니다.

React Router도 많은 사람들이 사용하고 있지만, Tanstack Route는 React Router보다 더 간편하고 빠르게 사용할 수 있습니다.

우선 Tanstack Route는 File-based Routing을 지원합니다.

File-based Routing이 아니라도 사용할 수 있습니다.

tanstack router의 가장 큰 장점으로는 자동 라우팅 코드 생성과, 강력한 타입 안전성을 들 수 있습니다.

잘못된 경로와 오타로 인한 라우팅 오류를 런타임 및 컴파일 시점에 잡아낼 수 있습니다.

그리고 Link 컴포넌트에서 to 속성을 통한 경로 자동 완성(Intellisense) 기능을 제공합니다.

요즘 핫한 React Framework인 Next.js에서도 기본적으로 File-based Routing을 사용합니다.

저도 주로 Next.js를 사용하고 있고, Code Based Routing을 사용하는 기존 React Router 방식보다, File-based Routing을 사용하는 Tanstack Route 방식이 더 편하고, Next.js와 비슷한 방식은 File-based Routing이기 때문에 더 편리하다고 느껴졌습니다.

이 글에서는 Tanstack Route의 사용법과 가이드를 알아보겠습니다.

목차

  1. Tanstack Route 설치
  2. 프로젝트 설정
  3. 프로젝트 파일 구성
  4. __root 파일 설정
  5. main 파일 설정
  6. 서브페이지 라우트 생성
  7. 추가 라우트 생성
  8. Header 컴포넌트 추가
  9. 서브페이지의 하위 라우트 생성
  10. 개별 Layout 설정

Tanstack Route 설치

설치

npm install @tanstack/react-router
# or
pnpm add @tanstack/react-router
# or
yarn add @tanstack/react-router
# or
bun add @tanstack/react-router

vite 프로젝트에서는 다음과 같이 두가지 패키지를 설치해야 합니다.

npm install -D @tanstack/router-plugin @tanstack/router-devtools
# or
pnpm add -D @tanstack/router-plugin @tanstack/router-devtools
# or
yarn add -D @tanstack/router-plugin @tanstack/router-devtools
# or
bun add -D @tanstack/router-plugin @tanstack/router-devtools

@tanstack/router-pluginvite 빌드 시 플러그인으로 사용되고, @tanstack/router-devtools는 개발 모드에서 개발자 도구로 사용됩니다.

위 설치 방법 외에 tanstack router에서는 간단하게 통합 패키지 설치를 지원합니다.

다음 명령어는 최초 설치시 해당 코드를 진행해 주세요.
npm create @tanstack/router@latest
# or
pnpm create @tanstack/router
# or
yarn create @tanstack/router
# or
bun create @tanstack/router

위 명령어를 실행하고 메세지에 따라 설치를 진행하면 됩니다.

프로젝트 설정

필요한 tanstack router 패키지를 설치하고 나면 프로젝트 설정을 진행해야 합니다.

우선 vite 플러그인을 구성합니다. 해당 파일은 vite.config.ts 파일입니다.

vite.config.ts
// vite.config.ts
import { defineConfig } from "vite";
import viteReact from "@vitejs/plugin-react"; // 또는 import viteReact from '@vitejs/plugin-react-swc'
import { TanStackRouterVite } from "@tanstack/router-plugin/vite";
 
// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    TanStackRouterVite(),
    viteReact(), // import 이름은 어느것을 사용해도 상관없습니다. (viteReact, react)
    // ...,
  ],
});
위 코드에서 만약 SWC를 사용하고 있다면 `import react from '@vitejs/plugin-react-swc'`를 사용해 주세요.

Import 이름은 Default Export라서 경로만 일치한다면 이름을 어느것을 사용해도 상관없습니다. (viteReact, react)

초기 vite 설치시 swc를 사용하고 있다면 import react from '@vitejs/plugin-react-swc' 경로를 사용해 주세요.

기본 설정은 간단하게 위와 같이 설정해 주면 됩니다.

이제 프로젝트에서 사용할 파일을 생성해 주어야 합니다.

프로젝트 파일 구성

프로젝트 파일 구성은 다음과 같습니다.

src
├── routes
│   ├── __root.tsx // 최상위 루트 파일
│   ├── about.tsx
│   ├── posts/
│   │   ├── index.tsx
│   │   └── $postId.tsx
│   │   └── ...
│   └── ... // 추가 라우팅 파일
├── main.tsx // 진입점 파일
├── routeTree.gen.ts // 자동 생성 파일
└── ...

프로젝트 파일 구성은 routes 폴더에 라우팅 파일을 생성하고, 최상위 루트 파일은 __root.tsx 파일을 생성해 주면 됩니다.

File-based Routing 방식을 사용하기 때문에 라우팅 파일을 생성하면 자동으로 경로 트리가 생성됩니다.

웹사이트의 페이지가 필요하다면 반드시 routes 폴더에 라우팅 파일을 생성해 주어야 합니다.

__root 파일 설정

이제 우선 가장 기본이되는 파일인 routes 폴더에 __root.tsx 파일을 생성해 주어야 합니다.

__root.tsx 파일은 프로젝트의 최상위 루트 파일입니다.

__root.tsx 파일을 생성하면 __root.tsx 파일에 별도의 코드를 작성하지 않아도 자동으로 라우팅 코드가 생성됩니다.

__root.tsx
import * as React from "react";
import { Outlet, createRootRoute } from "@tanstack/react-router";
 
export const Route = createRootRoute({
  component: RootComponent,
});
 
function RootComponent() {
  return (
    <React.Fragment>
      <div>Hello "__root"!</div>
      <Outlet />
    </React.Fragment>
  );
}
tanstack router에서는 라우팅 파일에 별도의 코드를 작성하지 않아도 자동으로 라우팅 코드가 생성됩니다.

tanstack router의 장점중 하나는 라우팅 파일에 별도의 코드를 작성하지 않아도 생성한 파일의 이름을 기준으로 자동으로 라우팅 코드가 생성됩니다.

그리고 __root.tsx 파일 코드 생성과 함께 routeTree.gen.ts 파일이 자동으로 생성됩니다.

생성된 코드를 살펴봅시다.

createRootRoute 메서드는 라우팅 트리의 최상위 루트 라우트를 생성합니다.

인자로는 라우트 컴포넌트와 라우트 옵션을 받습니다.

src
├── routes
│   ├── __root.tsx
│   └── ...
├── routeTree.gen.ts // 자동 생성 파일
└── ...

routeTree.gen.ts 파일은 생성된 경로 트리를 가져와서 자동으로 새 라우터 인스턴스를 만듭니다.

고로 routeTree.gen.ts 파일은 별도의 코드를 작성 및 수정하지 않습니다.

이제 main.tsx 파일을 설정해 주어야 합니다.

main 파일 설정

main.tsx 파일은 프로젝트의 진입점 파일입니다.

main.tsx
import ReactDOM from "react-dom/client";
import { createRouter, RouterProvider } from "@tanstack/react-router";
 
// 생성된 경로 트리 가져오기
import { routeTree } from "./routeTree.gen";
import { StrictMode } from "react";
 
// 새 라우터 인스턴스 만들기
const router = createRouter({ routeTree });
 
// 유형 안전성을 위해 라우터 인스턴스 등록
declare module "@tanstack/react-router" {
  interface Register {
    router: typeof router;
  }
}
 
// Render the app
const rootElement = document.getElementById("root")!;
if (!rootElement.innerHTML) {
  const root = ReactDOM.createRoot(rootElement);
  root.render(
    <StrictMode>
      <RouterProvider router={router} />
    </StrictMode>
  );
}

위와 같이 main.tsx 파일을 설정해 주면 됩니다.

App.css 및 App.tsx 파일은 더이상 사용하지 않으니 삭제해주세요.
만약 App.tsx 파일을 그대로 사용하고 싶다면 위 main.tsx 파일의 내용을 App.tsx 파일에 복사해 주세요.
최상위 루트 파일

최상위 루트 파일

Hello "__root"! 문구가 표시된 것을 확인할 수 있습니다.

앗! 그런데 Not Found 문구가 표시되는 것을 확인할 수 있습니다.

이것은 하위 라우트가 없기 때문에 발생하는 것입니다.

__root.tsx 파일은 최상위 루트 파일입니다. 자동으로 생성된 __root.tsx 파일을 자세히 보면 <Outlet /> 컴포넌트가 있습니다.

<Outlet /> 컴포넌트는 하위 라우트를 표시하는 컴포넌트입니다.

그러니 하위 라우트를 생성해 주어야 합니다.

서브페이지 라우트 생성

__root.tsx 파일에 하위 라우트를 생성해 주어야 합니다.

index.tsx 파일을 생성합니다. index.tsx 파일은 웹사이트의 메인 페이지를 의미합니다.

src
├── routes
│   ├── __root.tsx
│   ├── index.tsx
│   └── ...
└── ...

index.tsx 파일을 생성하면 자동으로 라우팅 코드가 생성됩니다.

index.tsx
import { createFileRoute } from "@tanstack/react-router";
 
export const Route = createFileRoute("/")({
  component: RouteComponent,
});
 
function RouteComponent() {
  return "Hello /!";
}

localhost:5173 주소로 접속하면 Hello /! 문구가 표시됩니다.

index.tsx 파일을 살펴 봅시다.

createFileRoute 메서드는 파일 기반 라우팅을 위한 라우트를 생성합니다. 인자로는 경로를 받습니다.

옵션으로는 라우트 컴포넌트를 받습니다.

__root.tsx 파일에 Hello "__root"! 문자가 있다면 함께 나타날 것 입니다.

__root.tsx 파일의 div 엘리먼트를 삭제하고 <Outlet/> 컴포넌트만 남겨둡니다.

index.tsx
// ...
function RootComponent() {
  return (
    <React.Fragment>
      <Outlet />
    </React.Fragment>
  );
}
<Outlet/> 컴포넌트는 반드시 남겨두어야 합니다. 그렇지 않으면 하위 라우트를 표시할 수 없습니다.

기본적으로 메인 페이지까지 설정이 완료되었습니다.

이제 tanstack router의 하위 컴포넌트 <Outlet/> 컴포넌트를 사용해 Header 컴포넌트를 추가하고 다른 페이지를 추가해 보겠습니다.

추가 라우트 생성

우선 추가 라우트를 생성하기 전에 라우트 트리를 살펴 봅시다.

src
├── routes
│   ├── __root.tsx
│   ├── index.tsx
│   ├── about.tsx
│   └── ...
└── ...

about.tsx 파일을 생성하면 자동으로 라우팅 코드가 생성됩니다.

src/routes/about.tsx
import { createFileRoute } from "@tanstack/react-router";
 
export const Route = createFileRoute("/about")({
  component: AboutPage,
});
 
// 함수 이름은 자유롭게 변경할 수 있습니다.
function AboutPage() {
  return "Hello /about!";
}

AboutPage 함수 이름은 자유롭게 변경할 수 있습니다. 단, 라우트 컴포넌트 이름과 동일해야 합니다.

라우트 파일을 생성하기 위해 파일 이름의 경로와 폴더 경로를 사용한 방법이 있습니다.

위에서 사용된 about 경로는 파일로 생성한 경로입니다.

파일 이름으로 생성한 라우트외에 폴더를 사용한 라우트도 있습니다.

src
├── routes
│   ├── __root.tsx
│   ├── index.tsx
│   ├── about/
│   │   ├── index.tsx
│   │   └── ...
│   └── ...
└── ...

두가지 방법중 어느것을 사용해도 무관하나, 저는 각 페이지별 라우트를 정리할 수 있는 폴더를 생성하는 방법을 선호합니다.

next.js의 라우팅 패턴도 폴더를 사용하는 방법이기 때문에 되도록이면 맞추는것이 좋다고 생각합니다.

about.tsx와 about/index.tsx의 차이점은 createFileRoute 메서드의 인자로 사용되는 경로입니다. about.tsx는 /about 경로를 사용하고, about/index.tsx는 /about/ 경로를 사용합니다. 폴더기준은 뒤에 /(슬러시)가 하나 더 붙어야합니다.

localhost:5173 주소로 접속하면 about 페이지가 표시됩니다.

이제 메인 페이지와 about 페이지가 완성되었습니다.

이제 Header 컴포넌트를 추가하고 Link 컴포넌트를 사용해 메인 페이지와 about 페이지를 이동해 보겠습니다.

Header 컴포넌트 추가

/components 폴더에 Header.tsx 파일을 생성합니다.

src/components/Header.tsx
import { Link } from "@tanstack/react-router";
 
const Header = () => {
  return (
    <header className="header">
      <h1>Tanstack Route</h1>
      <nav className="navigation">
        <Link to="/">Home</Link>
        <Link to="/about">About</Link>
      </nav>
    </header>
  );
};
 
export default Header;

Link 컴포넌트는 @tanstack/react-router에서 제공하는 컴포넌트입니다.

기존 react-router에서 사용하던 Link 컴포넌트와 동일한 기능을 제공합니다.

Tanstack Route에서는 강력한 타입 안전성을 제공하기 때문에 Link 컴포넌트에서 잘못된 경로가 있으면 즉시 오류를 표시하고 해당 메세지에서 경로 제안도 해줍니다.

Header 컴포넌트

Header 컴포넌트

이제 메인 페이지와 about 페이지에 Header 컴포넌트를 추가해 보겠습니다.

메인 페이지와 about 페이지에 모두 한번에 Header 컴포넌트를 추가하기 위해 __root.tsx 파일을 이용합니다.

__root.tsx 파일은 앞서 말한바와 같이 최상위 루트 파일입니다.

따라서 메인 페이지와 about 페이지에 모두 한번에 Header 컴포넌트를 추가할 수 있습니다.

src/routes/__root.tsx
// ...
export const Route = createRootRoute({
  component: RootComponent,
});
 
function RootComponent() {
  return (
    <React.Fragment>
      <Header />
      <Outlet /> {/* 하위 라우트를 표시하는 컴포넌트 */}
      <Footer /> {/* footer는 예시 */}
    </React.Fragment>
  );
}

<Outlet /> 컴포넌트는 하위 라우트를 표시하는 컴포넌트입니다.

<main> 엘리먼트 자식 요소로 <Outlet /> 컴포넌트를 추가할 수도 있습니다.

src/routes/__root.tsx
// ...
function RootComponent() {
  return (
    <Header />
    <main>
      <Outlet />
    </main>
    <Footer />
  );
}

이제 메인 페이지와 about 페이지에 각각 Header 컴포넌트가 추가된 것을 확인할 수 있습니다.

메인 페이지에 추가된 Header 컴포넌트

메인 페이지에 추가된 Header 컴포넌트

tanstack router에서는 Link 컴포넌트에 기본적으로 해당 경로와 일치하는 경로에 대한 active 클래스를 제공합니다.

이를 이용하여 현재 페이지에 대한 스타일을 쉽게 적용할 수 있습니다.

src/index.css
.active {
  color: yellow;
}

css 파일에서 .active 클래스를 사용하여 스타일을 설정할 수 있지만 Link 컴포넌트의 activeProps 옵션을 사용하여 스타일을 설정할 수도 있습니다.

src/routes/index.tsx
// ...
<Link
  to="/"
  activeProps={{
    style: {
      color: "red",
    },
  }}
>
  Home
</Link>

서브페이지의 하위 라우트 생성

tanstack-route에서 서브페이지의 하위 라우트를 생성해 보겠습니다.

about/ 폴더에 news.tsx 파일을 생성합니다.

폴더 구조는 다음과 같습니다.

src
├── routes
│   ├── __root.tsx
│   ├── index.tsx
│   ├── about/
│   │   ├── index.tsx
│   │   └── news.tsx
│   └── ...
└── ...

news.tsx 파일을 생성하면 이전과 같이 자동으로 라우팅 코드가 생성됩니다.

about/index.tsx 파일에서 Link 컴포넌트를 사용하여 news 페이지로 이동할 수 있습니다.

src/routes/about/index.tsx
// ...
<div>
  <h1>About</h1>
  <Link to="/about/news">News</Link>
</div>

Link를 클릭하면 localhost:5173/about/news 주소로 이동합니다.

만약 폴더기반으로 라우팅을 사용한다면 about/ 폴더에 news.tsx 파일을 생성해야 합니다.

src
├── routes
│   ├── __root.tsx
│   ├── index.tsx
│   ├── about/
│   │   ├── index.tsx
│   │   └── news/
│   │       └── index.tsx
│   └── ...
└── ...

다른 서브페이지도 동일한 방법으로 생성할 수 있습니다.

개별 Layout 설정

tanstack router에서는 개별 라우트에 대한 Layout을 설정할 수 있습니다.

여기서는 조금 복잡할 수 있습니다. 처음에는 이해하기 어려울 수 있습니다. 그러나 천천히 따라오면 이해할 수 있습니다.

개별 Layout을 설정하기 위해서는 이전 폴더 구조를 변경해야합니다.

예시로 about 페이지와 contact 페이지를 추가하여 각 페이지에 대한 Layout을 설정해 보겠습니다.

우선 _aboutLayout.tsx 파일을 생성합니다.

Layout 파일은 반드시 파일 이름 앞에 _(언더바)를 붙여야 합니다. File Based Routing 방식은 파일 이름을 경로로 사용하기 때문입니다.

_aboutLayout.tsx 파일은 해당 route 폴더와 같은 위치에 생성해야 합니다.

그리고 기존 about 폴더를 _aboutLayout 폴더로 감싸야 합니다.

폴더 구조는 다음과 같습니다.

src
├── routes
│   ├── __root.tsx
│   ├── index.tsx // 메인 페이지
│   ├── _aboutLayout/ // about 페이지의 Layout
│   │   ├── about/
│   │   │   └── index.tsx // about 페이지의 메인 페이지
│   │   │   └── news/
│   │   │       └── index.tsx // about 페이지의 news 페이지
│   ├── _aboutLayout.tsx
│   └── ...
└── ...

_aboutLayout/ 폴더를 생성하고 about 폴더를 드래그하여 _aboutLayout 폴더로 이동합니다.

만약 route 경로 에러가 난다면 routeTree.gen.ts 파일을 삭제하고 다시 실행해 보세요.

이제 _aboutLayout.tsx 파일을 설정합니다.

src/routes/_aboutLayout.tsx
// ...
import { createFileRoute, Outlet } from "@tanstack/react-router";
 
export const Route = createFileRoute("/_aboutLayout")({
  component: AboutLayout,
});
 
function AboutLayout() {
  return (
    <div>
      <h1>About Layout</h1>
      <Outlet />
      {/* 하위 라우트를 표시하는 컴포넌트, 반드시 추가해야 합니다. */}
    </div>
  );
}

<Outlet /> 컴포넌트는 반드시 추가해야 합니다. 그렇지 않으면 하위 라우트를 표시할 수 없습니다.

이제 네비게이션의 경로로 이동하면 About Layout 텍스트와 하위 라우트가 표시됩니다.

About Layout

About Layout

다음은 contact 페이지를 추가하고 해당 페이지에 대한 Layout을 설정해 보겠습니다.

방법은 about 페이지와 동일합니다.

_contactLayout.tsx 파일을 생성하고 contact 폴더를 _contactLayout에 추가한 후 index.tsx 파일을 생성합니다.

폴더 구조는 다음과 같습니다.

src
├── routes
│   ├── __root.tsx
│   ├── index.tsx
│   ├── _aboutLayout/
│   │   ├── about/
│   │   │   └── index.tsx
│   │   └── news/
│   │       └── index.tsx
│   ├── _contactLayout/ // contact 페이지의 Layout
│   │   └── contact/
│   │       └── index.tsx
│   ├── _contactLayout.tsx
│   └── ...
└── ...

이제 _contactLayout.tsx 파일을 설정합니다.

src/routes/_contactLayout.tsx
import { createFileRoute, Outlet } from "@tanstack/react-router";
 
export const Route = createFileRoute("/_contactLayout")({
  component: ContactLayout,
});
 
function ContactLayout() {
  return (
    <div>
      <h1>Contact Layout</h1>
      <Outlet />
    </div>
  );
}

나머지는 about 페이지와 동일하게 설정합니다.

이제 네비게이션의 경로로 이동하면 Contact Layout 텍스트와 하위 라우트가 표시됩니다.

Contact Layout

Contact Layout

위 이미지를 보시는 바와같이 aboutABOUT LAYOUT 텍스트가 나타나지 않는것을 확인할 수있습니다.

이는 about 페이지에 대한 Layout_aboutLayout.tsx 파일에 정의되어 있기 때문입니다.

또한 contact 페이지에 대한 Layout_contactLayout.tsx 파일에 정의되어 있기 때문에 contact 페이지의 CONTACT LAYOUT 텍스트가 나타나는 것을 확인할 수 있습니다.

이를 이용해 각 페이지의 디자인 및 기능에 대해 개별적으로 적용 및 관리할 수 있습니다.


마치며

이제 기본적인 tanstack-route의 각각의 경로 생성, 라우팅, Layout 설정 및 개별 Layout 설정 방법을 알아보았습니다.

내용이 길었습니다. 다음 포스팅에서는 tanstack-route에서 제공하는 다이나믹 라우트 및 쿼리 기능에 대한 블로그를 작성해 보겠습니다.

GitHub 코드

다음 GitHub에서 코드를 확인할 수 있습니다.

`Tanstack Route Basic`

참고

`Tanstack Router Docs`

관련 태그