最近、Remix ……いつの間にか統合されて React Router v7 を触っている。最初はなかなかいい感じと思っていたのだけど、実際に使ってみるとなかなかに厳しい。
Remix の哲学と言えばどちらかと言えばSSG (Static Site Generation)はやめてエッジで動的に生成しましょうという部分が強調されていたように記憶しているが、Pre-Renderingの機能も搭載されており、そこはすでに微妙な話なのかもしれない。
むしろ特徴的なのが「UI を永続的なサーバー状態と自動的に同期させる」という部分。詳細はRemix時代の「Fullstack Data Flow」を読んでいただきたい。
端的に言えば、HTML標準の動きをエミュレートするかのように旧来型のポストバック的な動作をReact で再現する設計になっている。ボタンを押し submit が行われると、そのアクションのサーバー処理が実行されるだけでなく、あわせて初期表示に使ったロード処理が再実行される。
ポストバック的な動作ではサーバーにある情報が正でクライアントにある情報はそのビューに過ぎないため、クライアントだけに存在するデータは不正確とみなされる。そのため、React Router v7 ではすべてのデータは loader で取得し、action ではデータの更新だけ行う(値は返さない)という設計が望ましいことになる*1。決して、action をリモートプロシージャコールとみなし結果を取得して画面に表示するなどという手続き的な作りにしてはならない。
個人的には React なり Vue なり近代的なUIライブラリを使う意義は、クライアント/サーバー型開発の復活にあると思っていたのだが、それとは真逆の方向性であることに気付かず、大変困惑する羽目になった。なぜ、こんなに感覚が合わないのだろうかと考えたのだが、私が業務システム開発の仕事をしているからなのかもしれない。昔、業務システムとWeb系システムの違いを考えたことがある。
- 業務システムは全社の膨大なデータから権限で許されたものを抽出して表示する。そのため、検索結果のキャッシュが難しく、検索には時間がかかる。
- Web系のシステムでは、誰もが同じデータを参照するか、ログインユーザに関するデータを見るかのいずれかしかない。前者はキャッシュできるし、後者は絞り込めるので検索は速い。
実際、業務システムでは1回ボタンを押したら数分返ってこないような処理も少なくない。コンシューマー向けの機能では許されないUXだが、業務システムには利用目的があり離脱はない。しかし、だからといってアクションの度にリロードされてはたまらない。
ASP.NET には ViewState という検索結果のようなフォーム以外の画面状態をセッション内で安全に保持できる仕組みがあったから良かったものの、Remix にはそれがない。だとすると、データはセッション変数に保持するしかなくなる。しかしセッション変数は同時更新に弱いという問題がのこる。
結局、いろいろ考えた末、shouldRevalidte を false にして再ロードを無効化してしまった(せざるを得なかった)。action の戻り値を取るためには actionData を useEffect で監視するしかないという不便さはあるが、そこさえ我慢すればクラサバ的に使えるのだ。