TanStack Routerとは?
TanStack Routerは、型安全で宣言的なルーターです。TanStack Queryなどの人気ライブラリを含むTanStackファミリーの一部になっています。TanStack Routerは、特にTypeScriptを前提に設計されており、既存のライブラリと比較して型づけをしやすくなっています。
React Routerとの違い
大きく違う箇所を挙げます。
ファイルベースのルーティング
React Routerでは、コード上でパスとコンポーネントの紐付けを行いました。
TanStack Routerでは、routes配下のパスで自動的にルーティングが決定します。
詳しくは後述します。
(React Router同様のコードベースのルーティングも可能、推奨はファイルベースです。)
型安全性の向上
パスやクエリパラメータに対し、簡単に型をつけることができます。
画像のように、定義済みのパスが補完で出てくるようになります。
TanStack Routerの使い方
TanStack RouterをViteプロジェクトに導入する手順です。
Viteが立ち上がっていない場合、
npm create vite@latest
でインストールをしてください。
インストール
まず、npmまたはyarnを使用してTanStack Routerをインストールします。
npm i @tanstack/react-router
Viteプラグインを設定する
ライブラリをインストールします。
npm i -D @tanstack/router-plugin @tanstack/router-devtools
npm i @vitejs/plugin-react
vite.config.tsにpluginsを追記します。
import { defineConfig } from "vite";
import viteReact from "@vitejs/plugin-react";
import { TanStackRouterVite } from "@tanstack/router-plugin/vite";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
TanStackRouterVite(),
viteReact(),
// ...,
],
});
ルートの定義
次に、アプリケーションのルートを定義します。
src/routes/__root.tsxを作成します。
import React from 'react'
import { createRootRoute, Link, Outlet } from '@tanstack/react-router'
import { TanStackRouterDevtools } from '@tanstack/router-devtools'
export const Route = createRootRoute({
component: () => (
<>
<div className="p-2 flex gap-2">
<Link to="/" className="[&.active]:font-bold">
Home
</Link>{' '}
<Link to="/about" className="[&.active]:font-bold">
About
</Link>
</div>
<hr />
<Outlet />
<TanStackRouterDevtools />
</>
),
})
HomeとAboutのコンポーネントを作成します。
import { createLazyFileRoute } from '@tanstack/react-router'
export const Route = createLazyFileRoute('/')({
component: Index,
})
function Index() {
return (
<div className="p-2">
<h3>Welcome Home!</h3>
</div>
)
}
import { createLazyFileRoute } from '@tanstack/react-router'
export const Route = createLazyFileRoute('/about')({
component: About,
})
function About() {
return <div className="p-2">Hello from About!</div>
}
main.tsxを次のようにします。
import { StrictMode } from 'react'
import ReactDOM from 'react-dom/client'
import { RouterProvider, createRouter } from '@tanstack/react-router'
// Import the generated route tree
import { routeTree } from './routeTree.gen'
// Create a new router instance
const router = createRouter({ routeTree })
// Register the router instance for type safety
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>,
)
}
import { routeTree } from ‘./routeTree.gen’
(routeTree.genはnpm run devで自動でできます)
これで準備が整いました!
この状態で「npm run dev」でサーバーを起動させます。
ブラウザを開くと、
__root.tsx、index.lazy.tsxの内容が表示されています。
/aboutに遷移すると表示が切り替わります。
__root.tsxで定義したヘッダー部分
<div className="p-2 flex gap-2">
<Link to="/" className="[&.active]:font-bold">
Home
</Link>{' '}
<Link to="/about" className="[&.active]:font-bold">
About
</Link>
</div>
が共通で表示されています。
<Outlet />
で定義した部分には、src/routes/index.lazy.tsxやsrc/routes/about.lazy.tsxで定義したコンポーネントが差し込まれています。
ファイルベースルーティング
実際にルーティングを追加してみます。
src/routes/posts/index.tsx
を作成します。
ファイルを作成するだけで、下記が自動で反映されるはずです。
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/posts/')({
component: () => <div>Hello /posts/!</div>
})
ヘッダーにリンクを追加します。
<Link to="/" className="[&.active]:font-bold">
Home
</Link>{' '}
<Link to="/about" className="[&.active]:font-bold">
About
</Link>
<Link to="/posts">
Posts
</Link>
ちなみに、「to」の箇所には補完が効いています。
これは開発しやすいですね!
/postsに遷移して確認します。
パスパラメータ
src/routes/posts/$postId.tsx
を作成します。
するとこちらもまた、自動で内容が反映されるはずです。
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/posts/$postId')({
component: () => <div>Hello /posts/$postId!</div>
})
/posts/1にアクセス。
次に、Reactコンポーネント側でpostIdを取得します。
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/posts/$postId')({
component: () => <PostComponent />
})
function PostComponent() {
const { postId } = Route.useParams()
return <div>Post {postId}</div>
}
Route.useParams()で、パスパラメータを取得できます。
クエリパラメータ
src/routes/index.lazy.tsxに、リンクを追加します。
import { createLazyFileRoute, Link } from '@tanstack/react-router'
export const Route = createLazyFileRoute('/')({
component: Index,
})
function Index() {
return (
<div className="p-2">
<h3>Welcome Home!</h3>
<Link
to="/posts"
search={{
page: 3,
filter: 'react',
sort: 'newest',
}}>Link</Link>
</div>
)
}
オブジェクトの形式でパラメータを定義できます。この例の場合、
/posts?page=3&filter=react&sort=newest
に遷移します。
TanStack Routerでは、さらに型をつけることができます。
src/routes/posts/index.tsxにvalidateSearchオプションを追加。
import { createFileRoute } from '@tanstack/react-router'
type ProductSearchSortOptions = 'newest' | 'oldest' | 'price'
type ProductSearch = {
page: number
filter: string
sort: ProductSearchSortOptions
}
export const Route = createFileRoute('/posts/')({
component: () => <PostComponent />,
validateSearch: (search: Record<string, unknown>): ProductSearch => {
return {
page: Number(search?.page ?? 1),
filter: (search.filter as string) || '',
sort: (search.sort as ProductSearchSortOptions) || 'newest',
}
},
})
function PostComponent() {
return <div>Hello /posts/!</div>
}
受け取る側を作成します。
パラメータはRoute.useSearch()で受け取ることができます。
function PostComponent() {
const { page, filter, sort } = Route.useSearch()
return <div>Hello /posts/! page: {page} filter: {filter} sort: {sort}</div>
}
型がつくようになっています。
クエリパラメータに簡単に型をつけることができる点も、大きな魅力に感じました。
イベントハンドラでの遷移
src/routes/index.lazy.tsxに、onClickで遷移するようなコードを追加します。
import { createLazyFileRoute, Link } from '@tanstack/react-router'
export const Route = createLazyFileRoute('/')({
component: Index,
})
function Index() {
const navigate = Route.useNavigate()
return (
<div className="p-2">
<h3>Welcome Home!</h3>
<Link
to="/posts"
search={{
page: 3,
filter: 'react',
sort: 'newest',
}} >Link</Link>
<hr />
<button onClick={() => navigate({
to: '/about',
})}>About Page</button>
</div>
)
}
useNavigateを使用しています。
React Routerとほぼ同じですが、toを指定する際に補完が出てくれます。
パラメータをつける時はこのようにします。
// クエリパラメータ
<button onClick={() => navigate({
to: '/posts',
search: {
page: 3,
filter: 'react',
sort: 'newest',
},
})}>Posts Page</button>
// パスパラメータ
<button onClick={() => navigate({
to: '/posts/$postId',
params: { postId: '123' }
})}>Post 123 Page</button>
まとめ
TanStack Routerを触ってみて、より型安全性が増したと感じました。
特にクエリパラメータに簡単に型をつけることができる点も、大きな魅力に思いました。
既存のライブラリだと実現しづらかった、細かい型付けにまで手が届いており使いやすい印象です。
ぜひ一度試してみてください!