今回のチュートリアルで作成したサンプルアプリは、Next.jsのApp Routerベースで作成してきました。
ところで、Next.jsのApp RouterではReactのServer Actions機能を提供しています。Server Actionsの有用な用途の一つはFORMの送信処理なのですが、実はクライアントからサーバサイドのTypeScript関数を型安全にリモート呼び出しができる汎用(はんよう)のRPCでもあります。従って、tRPCはServer Actionsと機能や用途がかぶっており、原理的に置き換えることができます。Creat T3 AppのイシューでもtRPCをServer Actionsで置き換えることについて議論されています。
参考に、本チュートリアルのサンプルコードのtRPC利用をServer Actionで置き換えてみた例を抜粋して以下に示します。
Server Actionsの定義(サーバ側)、src/app/_actions/todo.ts:
- "use server";
- :
- export async function getAllTodo(_formData: FormData) {
- return db.todo.findMany({ orderBy: [{ createdAt: "desc" }] });
- }
ここで定義しているgetAllTodo()はリモート呼び出し可能なServer Actionです。
Server Actionsの呼び出しコード断片(クライアント側)、src/app/_components/TodoList.tsx:
- const [isPending, startTransition] = useTransition();
- const [todos, setTodos] = useState<Todo[]>([]);
- :
- useEffect(() => {
- startTransition(async () => {
- setTodos(await getAllTodo({} as FormData));
- });
- }, []);
ここで、クライアントコンポーネントからServer ActionであるgetAllTodo()を通常の関数呼び出しのような記述でリモート呼び出ししています。なお、Server ActionをFORMからではなく直接呼び出すには非同期Transitionで囲むことが必要です。
tRPC版を比較のために以下に再掲します。
tRPCのルーター定義(サーバ側)、src/server/api/routers/todo.ts:
- getAll: publicProcedure.input(z.void()).query(async ({ ctx }) => {
- return ctx.db.todo.findMany({ orderBy: [{ createdAt: "desc" }] });
- }),
tRPCの呼び出しコード断片(クライアント側)、src/app/_components/TodoList.tsx:
- const [todos] = api.todo.getAll.useSuspenseQuery();
かならずしもコード量が減るという話でもないことが分かります。
tRPCがRESTful Web APIやGraphQLの「TypeScriptで特化型の簡易版」だとしたら、Server Actionsはさらなる簡易版でサーバ側の定義方法はtRPCよりも簡潔です。しかしながら、少なくとも現時点ではServer Actionsに対するtRPCの優位性もあります。例えば以下のような点です。
一方で、Server Actionsの優位な点は以下の通りです。
以上のように、それぞれの利点があり、今のところ「一般にどちらを選ぶべし」という判断は難しく、上記特質などを参考にプロジェクトの個別事情によって判断してください、という以上のことを言うのは難しそうです。
Create T3 Appは、Next.jsと他の主要なプロダクトをT3 Stackスタックとして連携させるための作り込まれたプロジェクトのひな型生成ですが、SSR、SSGに加えRSC、Server Actions、PPR(部分的事前レンダリング)など、Next.jsの機能が高度化した現在では、さらに有用性を増しています。
例えば、Next.jsはサーバとクライアントの両方にまたがってReactコードを協調実行することで高速な画面を構築しますが、Create T3 Appの生成する設定ではサーバ内で呼び出したtRPCの結果としてのTanStack Queryの状態キャッシュをクライアントにシリアライズして転送することで、クライアントでの初回表示を高速化させることができます(Tanstack QueryのHydration機能を使用)。このようなベストプラクティスはNext.jsのプロジェクトひな型作成ツールの中ではCreate T3 Appが群を抜いて作り込まれており、開始時のスタートラインとするメリットが大きいです。
もっとも、先のコラムで紹介したように、OSSは進歩も激しく、各OSSのバージョンアップ時に不安定になることはリスクとしてはあります。しかし、有用性が高く広く利用される機能であればあるほどフォークなどで問題が解決される可能性は高いでしょう。T3 Stackは長期的な有用性を吟味されたOSS群で構成されていて、その選定の正しさと強みは登場後2年余が過ぎた今、実績として証明されてきているように思えます。
そのことも含め、T3 Stackあるいはその実体としてのCreate T3 Appの強みは、コミュニティーが主導する形で開発がなされていることです。ひょっとしたらNext.jsを開発する企業Vercelは、T3 Stackで選定されているTailwindCSSの直接利用よりもVercel自身で開発したNextUIを使ってほしいのかもしれませんし、tRPCよりもServer Actionsで完結するサーバ機能呼び出しを主流として力を入れているかもしれません。しかし特にフロントエンド開発業界では、1社だけが主導する開発の形では活力が失われてしまうでしょう。
1つの企業の意図に従うのではなく、多くの開発者視点での利便性や機能性を広く集約する存在であることがT3 Stackを選ぶ理由になると筆者は考えています。
さて、連載を重ねて、回り道もしながらT3 Stackの構成要素を説明してきました。この間、当然ですがReactやNext.jsを取りまく開発事情は大きく変化し、T3 Stackに含まれるものではDrizzleが台頭してきました。またNext.jsのApp Routerの利用も普通になっていますしRemixなど他のフルスタックフレームワークの動向も興味深いところです。
T3 Stackは、T3原則に従い、えり抜かれた要素で構成されますが、長期的には同じままではなく、おそらく主に選択肢の追加の形で入れ替わっていくものであることは免れ得ません。例えば、App RouterやDrizzleが選択肢に増えたことがその一例です。しかし、T3 Stackはもともと疎結合の組み合わせなので、Next.js以外の取り外しは都合に応じて自由ですし、追加も自由です。実際、S3 Stack提唱者のTheo氏が最近アップロードしたモダンReact開発のチュートリアル動画ではtRPCは選択されずRSCを使用しています。
今回の連載では、そんな変化があることは前提にして、開発で求められる要件や性格に応じてライブラリ選択がどのようになされているか、T3 Stackを例として見てきました。
結局のところ、Create T3 Appを使おうが使うまいが、実際の開発プロジェクトにおいて、どんなライブラリやフレームワークを使用するかの取捨選択は必須です。その際に選ぶ基準は「たまたま知っているから」「最近見たブログ記事で良いと書かれているから」「誰かが使ったことがあるから」だけではないはずで、その選定眼を養うためにも、価値観や原則に基づいて選定されたT3 Stackは非常に参考になるものだと思っています。
先のチュートリアル動画のTheo氏の言葉を借りれば、T3 Stackは具体的なフレームワークであるだけではなく、マインドセット(考え方、ものの見方)であり、その価値観が読者のプロジェクトの在り方に沿うものであればT3 Stackは有用なものであるはずです。また、現実問題として個別にやるとバラバラになりがちな、プロジェクトの初期構成や初期設定を、実績ある共通形でできるジェネレータとしての価値も高いものです。
今回の連載では紹介しきれなかった「Auth.js」や「T3 Env」など興味深いコンポーネントも他にあるのですが、ここではいったん連載を終わらせていただきたいと思います。
ご愛読ありがとうございました。
※記載されている会社名、サービス名および商品名は、各社の登録商標または商標です。
ソフトウェア開発企業のNTTテクノクロスで、Gatsbyによる社内の技術情報ポータルサイト「Tech+Hub」の開発、運用や、React+TypeScriptを用いた開発支援や研修を担当。T3 Stackサイト日本語版訳者。書籍「プログラミングGroovy」主著者。
中学生以来、言語処理系の実装に興味を持ち続けている。
Twitter:@uehaj
Copyright © ITmedia, Inc. All Rights Reserved.
Coding Edge 鬯ョ�ォ�ス�ェ髯区サゑスソ�ス�ス�ス�ス�コ髣包スオ隴∵コキ�ク�キ�ス�ケ隴趣ス「�ス�ス�ス�ウ鬩幢ス「�ス�ァ�ス�ス�ス�ュ鬩幢ス「隴趣ス「�ス�ス�ス�ウ鬩幢ス「�ス�ァ�ス�ス�ス�ー