Remix: Reactの陰と陽

この記事はKent C. DoddsRemix: The Yang to React's Yinの翻訳です

私は2015年からReactのアプリを作り続けてきました。その時から、Reactは私の生産性を飛躍的に向上させる唯一無二の存在でした。Reactの状態に応じてUIをレンダリングする宣言型モデルは、私の考えるウェブのUIの構築方法を劇的に簡単にしました。また、ReactはAngular.jsやbackboneを使ってきたときの遥か先を行く、状態に関する素晴らしい考え方を与えてくれました。
Reactのタグラインは:

”ユーザーインターフェイスを構築するためのJavaScriptライブラリ”

Reactはこれを宣言型コンポーネントモデルを1番に開発し、提供することで見事に実現しています。状態管理なしではユーザーインターフェースを構築することはできません(コンボボックスのメニューは`open`なのか`closed`なのか?)。それが理由でReactはコンポーネントの状態管理ができるのです。
大事なのはウェブアプリケーションの要素はローカルのコンポーネント状態以外にもたくさんあるということです。実際、典型的なReactのアプリケーションで読み込まれる”状態”の大多数は、全くもって状態ではなく、サーバー由来の状態のキャッシュ(おそらくデータベースなど永続層から取得したもの)なのです。Reactは常に素晴らしい状態管理方法を提供しているとはいえ、我々が管理している状態の多くが実はキャッシュであり、キャッシングの問題に悩まされているという事実を隠すことはできません。

Phil Karltonの有名な格言が示す通り:

”コンピューターサイエンスには2つだけ難しいことがある:キャッシュの無効化と命名だ”

いろんな意味でこれはジョークですが、キャッシュの無効化は間違いなく難しい問題です。そしてこの問題を簡単にするために無数のライブラリやツールが開発されていることからもわかる通り、Reactは現時点まででキャッシュ問題の解決策をなにも提供してきませんでした。Redux (toolkit)、MobX、Apollo、React Query、SWRもしくはそれ以外など、ウェブ開発においてReactが下記の解決策を自前で提供してないという共通の問題のためだけにこれらのツールにたどりついているのです:

ネットワークキャズムの管理

ネットワークキャズムとは?

これがネットワークキャズムというものです:

ウェブデベロッパーとして、我々はクライアント側(ブラウザー側)とサーバー側で動くコードを書きます。我々はネットワークのコントロールはできません。そもそもこれが理由でキャッシュを考えなければいけなくなっているのです。ユーザーがタコスの選択🌮をするためにReactコンポーネントを再レンダーするとき、そのタコスで選べるオプションに同期的にアクセスする必要があります🤤。だからネットワークを介してHTTPリクエストを作り、再レンダーの時に使えるように、その値をReactの状態(もしくは何かしらのライブラリ)を使ってメモリ内キャッシュに保存します。
あなたは大規模・小規模両方のアプリで最もバグを引き起こす原因を知っていますか?

コードです。

ネットワークキャズムは大量のコードの源です。それを正しく扱うのは極めて困難ですが、ウェブサイトを作っているのですから挑戦しなくてはなりません。結果、JavaScript、今どきのfetch API、便利なライブラリを駆使してHTTP経由でネットワークキャズムをまたいでバックエンドとデータをやりとりするための架け橋を作り込むことになります。

この架け橋に必要なコードは全てフロントエンド側にあります。データの取得においては、どのデータを取得するべきか把握する必要があり、たいていの場合データを取得するコードとそのデータを使うコードを同じ場所に置きたい(こうするとバグ/ミス/余分なデータの取得が大幅に軽減されます)と思うので難しい問題となります。これにはコンポーネントがレンダーされるまでデータを取得できないという残念な副作用があります。

それに加え、アプリの読み込みをより速くするためにコード分割を分割しようとすると、コンポーネントのレンダーだけでなく、レンダーが始まってしまうとそれに必要なコードの読み込みもしなくてはいけなくなります。これはネットワークウォーターフォールを引き起こすのです(我々はウォーターフォールの危険性については皆知ってますよね)。

残念ながらデータの読み込み自体はこの問題を解決しません。実際、データ読み込みのためのReact Suspenseでさえ解決することはできません。Suspenseはコンポーネント内からデータを取得するようなデータ取得用のライブラリにとって変わることができます(そして、データがまだキャッシュされてないならそうするようにデータを誘発します)がウォーターフォール効果を避けたい場合は、これらのコンポーネントのコードがレンダリングされる前にデータのフェッチを開始する必要があります。

より早い読み込み

これこそ私が、React Routerがこの問題を私がRemixで気に入ってるところの多くを取り入れることで解決しようとしていることにとてもワクワクしている理由です。Ryanはこのことについて彼の投稿React RouterをRemixすることの中で語っています。レイアウトネストルーターと`loaders`(データの取得)及び`actions`(データの書き換え)のおかげで、コンポーネントとデータ取得を切り離すことができますが、コロケーションの恩恵は受けることができます。このデータ取得はこの場合、コンポーネントのではありませんがネストされたレイアウトルーターのおかげてとても近い位置にあります。

これらの機能により、我々は"レンダーしないとデータの要件がわからない"というところから、"URLからデータの要件がわかる"というところまで来ました。

さらに、React Routerは今ではあなたの代わりにネットワークキャズムの一部を管理してくれます。それが意味するところは、ローディング/エラー状態を気にかける必要がある自前のコードを大幅に削減できるということです。また、React Routerがキャッシュの再検証を行えるということでもあります!おっと、そしてフォームの再送信と競合条件もです(UIの開発における難題の一部)。さらに、優れたユーザーエクスペリエンス(楽観的UIなど)の構築がかつてないほど簡単になりました。これにより実質的にネットワークキャズムを少々狭めることができます:

もっと改善できないか?

これらの機能がReact Routerで利用できるということは、コードを簡素化したい人やアプリを高速化したい人なら誰しもにとって大きなメリットです。React Routerはデータ取得のためのReact Suspenseと(おそらくMetaは持ってるであろうinfrastructure/compiler/routerを持たない限りは)最も親和性が高くなるでしょう。

しかし我々はもっと改善できます。一度ブラウザの読み込みを早めたとしても、最初のJavaScriptバンドルが表示され、実行されるのを待たないことにはユーザーは何も見えません。データの読み込みや書き換えの管理を手助けしてくれるReact Routerを使えば、状態(キャッシュ)の管理するコードの多くを削除できますが、それらの全コードはまだブラウザー上にあります。さらに、我々はデータ取得後のコードがデータ取得のためのコードの前に必要なので、これはコード分割ではなくなっているのです。

もし仮に、そのコードをすべてブラウザからサーバーに移すことができたとしたら、素晴らしいことだと思いませんか?データベースとのやり取りや秘密鍵を必要とするAPIを叩く必要があるたびにサーバーレス関数を書く必要があるのは煩わしいことではありませんか?(はい、そうです)。これらはReact Server Componentsがやってくれるを我々に約束し、我々は確かにそのデータ読み込みを待ち望んでいますが、React Server Componentsは書き換えに関しては何もしてくれず、やはりコードをブラウザーの外に出すことができれば(リリースを待つ必要がなくなるし)良いと思うのです。

右のステージに入る:Remix 💿

あなたのアプリを次のレベルに進化させるようとすると、サーバ側でアプリをレンダーしたくなるでしょう。そしてそれを実現する最善策がRemixを使うことなのです。Remixはネットワークの境界の架け橋を、あたなが何も考えなくて済むように仕上げてくれます。データ取得やデータ書き換えのコードを従来の「Remix ルートモジュール」エクスポートされた関数に移動させるや否や、Remixが全てのネットワークキャズムを処理するようになります。

今やあなたのアプリはユーザーがJavaScriptを読み込むのを待つ必要がないので本当に空を飛ぶことができます⚡️。アプリはそこにあり、ユーザーのために準備されています(そして、プログレッシブエンハンスメントのおかげで、裏でJavaScriptがダウンロードされている間、すべてのリンクとフォームも機能します)。

そしてこれを手に入れれば、今あなたはサーバー上で動作するコードを書くことができるようになったので、データベースを直接呼び出すことや、秘密鍵でAPIを叩いたりすることを心配する必要はもうありません。ローダーやアクションはサーバー上でしか動作しなくなるので、あなたが必要なことは何でもできるようになります。素晴らしいDXの改良です!

アプリ全体について

Remixがサーバー側の力をあなたに与えるということは、実はあなたは必要であればアプリ全体の処理ができるということを意味します。全ての人がそうしたいわけではありませんが、データベースや関連するサービスと直接やりとりができるバックエンドを扱えるということは、どちらかというとこのような構成のアプリを作ることが可能です:

すごいのは、ネットワークキャズムを完全にコントロールするというメリットを100%Remixを使っても、そうでなくても全て得られるというところです。つまり、既存のバックエンドに満足してるのであれば、もちろんそれを使っていいのです。

結論

Reactのタグラインは:

”ユーザーインターフェイスを構築するためのJavaScriptライブラリ”

そしてそれに関してReactは凄まじい仕事をしています。Reactは一度も”ネットワークキャズムの管理”を約束したことはありませんが、全てのウェブアプリケーションがそれが必要なのです。ネットワークキャズムを管理するRemixを使うことで、我々はようやくReactの陰から陽の部分を得ることができました。素晴らしいレンダリングライブラリと強力なネットワークキャズム管理により、より良く、より速いウェブアプリケーションをより少ないバグ、より簡単なコードで、そしてより楽しく作ることができます。

私ごとですが、これが私がウェブアプリをRemixで構築することにぞっこんな理由です。あなたが今日この記事を読んでいるウェブサイトは、Remixに書き換えた結果です。 始めた当初はそれがどんな素敵なものになるか、まったく思いもよりませんでした。Remixは全てを可能にしました。なぜなら、基本的な機能を完成させたとき、もっと多くのことをする時間と能力があるということに気づいたからです(より詳しいことは私がサイトの再構築をした時について読んでみてください)。Remixは私の持っていた楽しいアイデアに「イエス」と言える気持ちにさせてくれ、そのことがとても新鮮でした。

あなたのより良いサイト作りのお役に立てれば幸いです。
いつもクールで😎

※誤訳などはコメント等でお知らせいただけますと幸いです。

この記事が気に入ったらサポートをしてみませんか?