TanStack Routerという選択肢
TanStack Routerを使った型安全なルーティング
Next.jsやRemixなどのフレームワークを使用するほどではないけど、SPAでルーティングを使いたい時がありTanStack Routerを採用してみました。
個人的にはフレームワークを使用しないのであれば良い選択肢の一つだなと思いましたので良かった点をまとめてみます
1. 型安全なルーティング
ファイルベースのルーティングは確かに便利ですが、型安全性の観点からは不安が残る部分もあります。TanStack Routerでは、ルーティングに型を付けることができるため、型安全にルーティングを実装できます。
これは2024/10/20現在Next.js
でもexperimentalな機能として提供されていますが、使用感はTanStack Routerのほうが優れていると感じました
.lazy
でバンドル分割
2.
TanStack Routerでは、ファイル名に.lazy
を付けることで、ページごとにバンドルを分割できます。たとえば、routes/about.lazy.tsx
の形式で指定すると、そのページはアクセス時に初めて読み込まれます。これはReactのlazy
importと同様の仕組みです。
loader
でデータ取得
3.
TanStack Routerには、ページにアクセスした際にデータを取得するためのloader
APIが組み込まれています。loader
を使うことで、データを事前に取得し、それに基づいてページを描画できます。
import { createFileRoute } from "@tanstack/react-router";
async function loaderFn() {
await new Promise((res) => {
setTimeout(res, 1000);
});
return "hoge";
}
export const Route = createFileRoute("/posts/$postId")({
loader: async () => {
const data = await loaderFn();
return {
data,
};
},
component: Post,
});
import { Await, createFileRoute, defer } from "@tanstack/react-router";
async function loaderFn() {
await new Promise((res) => {
setTimeout(res, 10000);
});
return "hoge";
}
export const Route = createFileRoute("/posts/$postId")({
loader: async () => {
const data = loaderFn();
const data2 = await loaderFn();
return {
data: defer(data),
data2,
};
},
component: Post,
});
function Post() {
const { data } = Route.useLoaderData();
return (
<div>
<h1>Post</h1>
<span>{data}</span>
</div>
);
}
ただし、loader
の処理が完了するまでページの描画が行われないため、待機中のコンポーネントを表示したい場合にはpendingComponent
を指定できます。
export const Route = createFileRoute("/posts/$postId")({
loader: async () => {
const data = await loaderFn();
return {
data,
};
},
pendingComponent: () => <div>loading...</div>,
component: Post,
});
こうすることで、loader
が終わるまでpendingComponent
が表示されるようになります
ただ、loader
で取得したデータが必要な部分以外は先に表示しておきたい場合もあります
そのときは次に紹介するdefer
とAwait
コンポーネントを使用して解決できます
defer
とAwait
コンポーネント
4.
ページ全体の描画を待たずに、必要なデータが揃っていない部分以外を先に表示したい場合、defer
とAwait
コンポーネントを使うことで柔軟に対応できます。
import { Await, createFileRoute, defer } from "@tanstack/react-router";
async function loaderFn() {
await new Promise((res) => {
setTimeout(res, 10000);
});
return "hoge";
}
export const Route = createFileRoute("/posts/$postId")({
loader: async () => {
const data = loaderFn();
return { data: defer(data) };
},
component: Post,
});
function Post() {
const { data } = Route.useLoaderData();
return (
<div>
<h1>Post</h1>
<Await promise={data} fallback={<div>loading...</div>}>
{(data) => <div>{data}</div>}
</Await>
</div>
);
}
この方法を使うことで、ページ全体を表示しつつ、データの取得が完了するまでは指定したfallback
コンポーネントが表示されます。
まとめ
今回使用したのは小規模なツール開発だったため、ルーティングライブラリとしてTanStack Routerを採用しましたが、より大規模なサービス開発では、Next.jsやRemixのようなSSRやRSCなどのサーバーサイド機能を備えたフレームワークの方が、パフォーマンスやバンドルサイズの面で優れていると思います。
ユースケースによっては、TanStack Routerも選択肢の一つとして検討する価値があると感じました。
他にも機能を兼ね備えているので、いろいろ使用してみたいと思います
Discussion