Open6

ReactのAtomic State ManagementとSignalの動向を追う

導入

最近のReactの状態管理ライブラリがスケールした先はstore自体をVanilla化して脱Reactする傾向にある。
(Zustand, Jotai, tanstack query, ...etc) [1][2]

理由として、Reactのコンテキストでstoreを持つと以下のような問題がある。

  • useMemo, useCallbackなど本質的にノイズなコードが必要
  • Reactのimmutableな制約の影響を受ける

storeをVanillaにすると

  • storeに対するget, setを自然に表現できる
  • インスタンスが変わらない(参照が同じ)なのでレンダリングのチューニングの余地がある

そして火付け役としてuseSyncExternalStoreがReact公式から提供された。
これを利用するとVanillaでもReact18以降のセマンティクスに対応してtransition, concurrentのメリットを享受できる。
もはやVanillaでstoreを持つことのデメリットは消えつつある。
以前と比較してstoreとReactを連携するためのルールやコードは遥かに減っている。

Vanilla化するとコードベース全体もシンプルになっていく。
というのも、プログラムの複雑性はドメインモデルと技術基盤の乖離の係数(いわゆるインタフェースを合わせるためのボイラープレート)によって増すという解釈(筆者独自)からすると、storeの基盤をVanillaにすると技術基盤の乖離が減り、ドメインモデルをより純粋かつ自然に表現できるようになるからだ。
Reactにおけるドメインモデルと技術基盤の乖離についての具体例は https://zenn.dev/link/comments/238de1fb4a497d に詳細を記している。
React Hooksでドメインモデルを表現することには限界がある。

界隈として、今まで本当はstoreをVanillaにしたかったが、Reactの制約によって難しかったのだろう。
それがReactの進化によって可能となった、とも言える。
useSyncExternalStore, transition, concurrentなど、ReactのDXとUXを両立させる進化はめざましい。
そのような背景から状態管理を脱Reactする流れが生まれてきたのだと思う。

それが結果的に設計をシンプルにし、Islands ArchitectureのようなReact以外の選択肢を増やすきっかけにもなる。

論点

Vanilla化したstoreに対しreactivityをどう実現するかが論点となるが、大まかに2パターン存在する

  1. observer, proxyを組み合わせる (ここでは便宜上signalパターンと呼ぶ)
  2. ReactのuseSyncExternalStoreを使うパターン

本スクラップでは前者のsignalパターンの動向を追う。
なるべく中立的に各ライブラリの思想とトレードオフを挙げていく。
また、個人的にAtomic State Managementを多用するので比較対象としてRecoil, Jotaiを挙げている。

登場人物

Atomic State Management

Signal

関連するReactのコア機能

  • パラダイムシフトの可能性を秘めているモノたち

  • React Forget

    • まだ研究中
    • ReactのコンパイラでuseMemoを動的に作るやつ
  • use

    • promiseを第一級オブジェクトとして扱う
    • 将来的にはcache apiという形でstoreを持つ予定
  • Support Promise as a renderable node

    • promiseをレンダリング可能なノードとして扱う
脚注
  1. Form系ライブラリはあまりVanilla化されてないが、これはフォーカス管理などでrefが必要になることに起因している?作ろうと思ったら作れそうだが、複雑なForm State管理の需要は低いのか? ↩︎

  2. この領域の先駆者は dai_shi 氏と Tanner Linsley 氏だと思う。https://twitter.com/dai_shi/status/1434543349524877317, https://twitter.com/tannerlinsley/status/1504907291291623427 ↩︎

jotai-signal

legend-state

まだ調べきれてないこと

  • Suspense対応
  • testing

所感

  • 第一印象としてはRecoil, Jotaiよりも柔軟性が高くて抽象化の筋が良いと思った
  • アプリの設計の文脈でいうと、スケールに合わせてreducerやaction的な概念でステートをひとまとめに更新したくなるので、そのあたりの知識は普遍的に必要
    • 最初にポリシー定めておくのは大事
      • いつでもどこでもmutableに変更しちゃうと後から破綻する
      • MVVM時代に後戻りしないように
    • コンポーネントを横断する際は適切にlifting state upするとよさそう
ログインするとコメントできます