Server Actionsがかなりキツイという話
さて,相も変わらぬフロントエンドは発展途上なわけでありますが,Next.jsのServer ActionsがStableになってしばらく経ちましたが,みなさまはいかがお過ごしでしょうか.
Server Actionsを本格的に使ってみたので例を上げながら所感を述べたいと思います.
タイトルに,「キツイ」という曖昧な表現をしましたが,ネガティブな意味はなく,概ねはServer Actionsの使用感には満足しています.ただ,今のところ手が届かないことが多いように感じました.
Server Actionsのベースとなる書き方
一般的にServer Actionsを使うのはCRUDのCUDです.
Next.jsのApp Routerでは,テータの取得にServer Actionsは使いません.(理由も割愛)
なので,サーバー側にフロントエンド側で扱っている何かしらのデータを送信したいときに使用します.
公式にあるシンプルな例がこちら
今回はこの形を維持して,本を新規作成するComponentを考えます.
本のデータの保存の処理はprismaを使用するものとし,
このComponentの責務は入力したデータをDBに保存してその結果をUIとして表示するものとし,
それらの責務はこのComponent内に閉じたいとします.
今はまだ本のデータを保存することをしか満たしていません.
サーバー側の処理をファイル分割したい
今回で言うprismaを使用したDBのCUDの処理は実際の開発ではファイル分割したいことでしょう.
こうなります.
こんな感じです.
CreateFormはuse clientを宣言しないとエラーになったと思います.
サーバー側の処理結果をフロントエンドで知りたい
このままではデータの保存に成功したのかをフロントエンドは知ることができません.結果に適したUIを表示するためにもREST APIのResponseと同様の結果がフロントエンドにも必要になります.
さてここから書き方が人によって分かれてくるところです.
大きくは2つだと考えています.
useFormStateを使用するパターン(おそらく推奨)
1つはReactが提供するuseFormStateを使用する方法です.
これを使用することで,htmlだけでサーバーにデータを届けることができ,いろいろいいことがありそうです.
formStateというものを自分で定義することでハンドリングできます.この場合サーバー側の関数を以下のように書かなければなりません.
おまけにバリデーションの処理も追加してみました.
これは一つの例ですが,このようにformStateの型は自由度が高くプロダクトごとに大きく異なることになるでしょう.
これはREST APIのようなResponseの形式をこちらで決めるということです.
今回は
のようにしました.
errorとvalidationErrorは統合してもいいかと思います.
こうすることで,サーバー側の実行結果をformStateとして受け取ることができるようになり,エラーを動的に表現することができます.
例えばValidateErrorは,
のように書けば動的に表現できます.
しかし,JSXにそのまま書く類のものは動的に表現できますが,結果による処理を実行する方法が私は未だに見つかっていません.
思いつく方法は以下のようにuseEffectを使用して処理を走らせる苦肉の策です.
また,この場合でさらにLoading状態をUIで表現したいとします.
その場合は<button type="submit">Submit</button>の部分をComponent分割しなければなりません.
以下のようにして,useFormStatusを使用することで実現できます.
という実装が推奨されている方法のようです.
縛られる部分と自由すぎる部分は混ざり合っており,開発体験はなんとも言えない感じになりそうです.
jsで自由にハンドリングするパターン
続いては上のパターンを知らない人が思いつきそうなパターンです.
これであれば,Loadingやエラーすべてのパターンをいつものように記述できそうです.
デメリットを上げれば,
HTMLだけで実行する恩恵を得られないというのと,
createBookの処理だけがサーバーサイドであるということがわかりずらくカオスであることでしょうか.
また,web上を探してもこのように実装している例は見つかりませんでした.
Optimistic updatesを使用するパターンもある
また,Optimistic updatesを使用する手法もありますが,試してないのと,実装に複雑味が増すので好ましくないと考えているので,今回は省きました.
あとはuseTransitionを使用してonSubmitする方法もあったような.
もうキツイ
いかがでしょうか.
何がキツイのかはあえて書きませんが,
実際に実装するともっと多くのことを考えなければならずに更にキツイことが増えるかと思います.
しかし,これらは今までの固定概念があるとよりキツイと感じてしまうとも言いかえられます.
個人的には
フロントとサーバーで型を一貫して使用できる
APIのエンドポイントを作成しなくて済む
フロントエンドのバリデーションが不要になった
フロントエンドのuseFormという概念が不要になった
という点だけで非常に開発体験は良いと感じました.
また,これまで複雑に実装しがちであったフロントエンドもこれによってシンプルにすることもできると考えています.