React Compiler 時代における状態管理ライブラリについての考え、RSC も重要
こんにちは、ZustandとJotaiとValtioの作者です。しばらく前に、React Compiler時代における状態管理ライブラリについて思うところを書いたので、よろしければご覧ください。
以下、ChatGPTによる翻訳です。
はじめに
私はこれまで、React の状態管理ライブラリである Zustand、Jotai、Valtio の 3 つを開発してきました。では、React Compiler と React Server Components(RSC)が登場する新しい時代において、これらはどう生き残っていくのでしょうか?この記事では、その場の思いつきも含めつつ、いくつか考えを書いてみます。
状態管理ライブラリとは?
状態管理ライブラリは、アプリケーションの状態を管理するためのものです。私が作っているライブラリに関して言うと、主目的は「状態をどう管理するか」だけではありません。これが 3 つのライブラリが存在する理由でもあります。状態の扱い方(たとえば immutable、atomic、proxy など)や、開発者が状態をどう運用するかがそれぞれ異なります。
私が「グローバル状態ライブラリ」と呼んでいるものの主目的は、React の状態管理手段である useState と useContext の制約を乗り越えることです。React Context は、状態のごく一部が変わっただけでも React が再レンダーを発生させてしまうため、不要な再レンダーを避けるのが難しいという問題があります。グローバル状態ライブラリは、状態変化を購読(subscribe)する独自の仕組みを提供し、効率よく再レンダーをトリガーすることでこの問題に対処します。
React Compiler は何を変えるのか?
React Compiler は React のユーザーコードを変換し、完全なメモ化を備えた最適化コードを生成します。要するに、useMemo、useCallback、React.memo といった手動のメモ化が不要になります。では、これがグローバル状態ライブラリにとってなぜ重要なのでしょうか?
本質的には、React Compiler が React Context の制約を解消する方向に働くからです。執筆時点では再レンダー最適化はまだ行いませんが、十分に高度化すれば、React は Context を使っていても不要な再レンダーを避けられるようになるかもしれません。つまり、グローバル状態ライブラリが解決しようとしている中核の問題が消えてしまう可能性があります。
React Server Components はどう関係するのか?
React Server Components(RSC)は、React コンポーネントをサーバーでレンダーし、シリアライズされた結果を通信経由で送れるようにする仕組みです。これは強力な機能ですが、グローバル状態ライブラリに影響はあるのでしょうか?
React Compiler に比べると、RSC の影響はより間接的です。ただし、グローバル状態ライブラリの中にはサーバー状態のキャッシュ用途で使われているものもあります。開発者がすでに別のライブラリを使っているケースも多いですが、もしグローバル状態ライブラリがサーバー状態のキャッシュを担っているのなら、RSC によってその必要性が下がる可能性があります。そうなると、グローバル状態ライブラリに残る役割は最小限となり、複雑な状態を「管理」する必要がなくなるかもしれません。
生き残るためにグローバル状態ライブラリは何をすべきか?
述べたとおり、グローバル状態ライブラリの主目的は不要な再レンダーを避けることです。しかし価値はそれだけではありません。状態の整理方法、状態の合成(compose)の方法、外部サービスとの接続など、さまざまな能力を提供します。たとえ主目的が不要になったとしても、こうした能力は依然として有用です。
さらに、クライアント側の状態がサーバー側の状態とシームレスに連携できるようにするのは強力な機能になるでしょう。サーバーとのやり取りを単純化し、開発体験を向上させられます。まだ具体案があるわけではありませんが、私が Waku の開発を始めた理由の一つでもあります。
それでは、各ライブラリを簡単に見ていきましょう。
Zustand
セレクタによるレンダー最適化はもちろんですが、Zustand の最大の利点は「状態が React の外に存在する」ことです。Context を使った React の状態管理ではこの点を解決できないため、Zustand は今後も役割を持ち続けるでしょう。
Zustand にとって最大のリスクは、そのシンプルさです。Compiler 時代には、より直接的で分かりやすい解決策を提供する新しいライブラリが登場し、置き換えられる可能性があります。ただしシンプルさは強みでもあります。誰でもメンテナンスできるので、長期的にも生き残りやすいでしょう。
Jotai
Jotai は当初、余計な再レンダーを避ける目的で設計されましたが、Recoil によって広まった「atom」という新しい原則も取り入れました。atom によって、状態を React の外で定義しつつ、React の内部で管理し続けることができます。Jotai には atom の値を React の外側で保持するストアを作るオプションもあります。atom モデルの強みは、宣言的で合成しやすい点にあり、複雑な状態を扱うためのデータフローグラフを構築できます。
Jotai の最大のリスクは、多くのユーザーがそこまで複雑な状態を管理する必要がないかもしれないことです。より単純な用途であれば、Context を使った React の状態管理で十分になり得ます。しかし、宣言的な atom モデルをサーバー側へ拡張できれば、有望な方向性になるかもしれません。
Valtio
Valtio には大きく 2 つの側面があります。1 つ目は、mutable な状態と immutable な状態のギャップを埋めることです。JavaScript のオブジェクトは本質的に mutable であり、valtio/vanilla は mutable な状態から immutable なスナップショットを導出する方法を提供します。2 つ目は、valtio/react が proxy を使ってレンダー最適化を提供し、それが裏側で“魔法のように”動く点です。
Valtio のレンダー最適化は、概念的には React Compiler と衝突します。ランタイムの解決策とビルド時の解決策だからです。とはいえ、Valtio v2 は React Compiler と完璧に共存できます。Compiler 時代には 2 つ目の価値が薄れる可能性がありますが、1 つ目の「素の JavaScript オブジェクトで状態を管理する」能力は非常に有用なままです。この能力を提供するライブラリは多くありません。
おわりに
グローバル状態ライブラリの将来に不安を感じる部分はあるものの、すぐに何かが変わるわけではありません。React Compiler はまだ実験段階で、RSC もまだ新しい技術です。人々がこの新しい時代に適応するには時間がかかります。その間、グローバル状態ライブラリは React エコシステムの中で引き続き役割を果たすでしょう。
述べたとおり、この 3 つのライブラリは新しい時代でも価値を持ち続けます。ただし、将来も生き残れるように手を打つべきだとも感じています。結局のところ、進化しなければ長くは続きません。
Discussion