Chapter 09

2章.3 リビルド状態管理:中央から分散

Satoshi Takeda
Satoshi Takeda
2021.09.30に更新

Flux 以降、状態管理はどうなってしまったのか

Flux が登場してから Store や Action などといった要素を携えた状態管理のライブラリがいくつか作られました。ライブラリ・フレームワークによってデファクトになったものもあれば、新しいソリューションを提案しているものもあります。

我々が状態管理と呼ぶものに求めるのは、SPA ないしはフロントエンド中心の Web アプリケーションにおいて「オンメモリ上にデータを Write/Read できる」「データの変更検知で UI に反映できる」といったシンプルな機能です。Read した値は Observable であるか、もしくは PubSub などに類似した機構を持つかの違いはあれど、開発者の認知レベルに応じて UI を更新するしくみを備えているはずです。

Global State ↔ Read/Write ↔ UI Library Binding

Flux や Redux などの状態管理自体は UI ライブラリに限定される考え方ではありません。Redux が react-redux を提供していたり Redux をベースとしたデータフローを汲んだ Angular 向けの NgRx があったりと、UI ライブラリに適用した形や派生はいくつかあります。

Smalltalk MVC

Flux が提示したデータを UI へ反映する手法は新しいものではありません。いくつか言及はありますが、Smalltalk の提示した GUI を実現するための MVC アーキテクチャの焼き直しです。

Smalltalk MVC

上記コードでは View-Controller を一緒くたにしていますが Model のデータを更新(Write Data)するための操作具であるボタンを押下(Handle)します。その後、Model は View にイベントを通知し(Event Messaging)、View は Model の更新を知りデータを再度読み取ります(Read Data)。

Redux で同様の UI をトレースしたものを確認いただくと分かりますが、ボタン押下で Action が発行されると Store にある State が更新されます。View は Store を Subscribe しているので、メッセージを受け取ると View を更新します。

Redux

Recoil のもたらした状態管理の、その先

Recoil は完全に React のためのものです。Hooks API に準ずるような API を備えており、Action や Reducer など Flux 以降が定義してきた State 更新のためのキャラクタが登場することはありません。

Recoil が提供する概念は Atom と呼ばれる最小単位の State、そして Atom を useState のように扱える API でここまでの実装を容易に再現できます。下に示した counter はほかのコンポーネントからも取り回し可能な Global State です(実際にはコンポーネントの上流に Provider のような RecoilRoot コンポーネントが必要です)。

const counter = atom({ key: 'counter', defalut: 0 });
const Counter = () => {
  const [count, setCount] = useRecoilState(counter);
  const increment = () => setCount(count + 1);
  return (
    <>
      <p>{count}</p>
      <button onClick={increment}>inc</button>
    </>
  );
};

React の強烈なイデオロギーをそのまま状態管理へと昇華させてしまった Recoil が到達したのは、シンプルな、ざっくり言えば値の参照と更新がそこにあるのみです。Store のような中央管理もなく、名の通り原子レベルで分散しています。

Recoil

Redux が中央管理していた Store はそこにはなく、UI コンポーネントがそれぞれ関心のある Atom と接続している点は、Container/Presentational といったコンポーネントの粒度でバケツリレーする設計からさらに違った設計ができそうです。コンポーネントを志向してきた現代において、UI へ適用しやすい状態管理として候補にあげることもできるでしょう。

Global State ↔ Read/Write on React

ただし React と大きく紐付いているのは前述のとおりで、現状 React の上でしか成立しません。また、ライブラリが提供する簡便な API を利用するだけではなく、アプリケーションが成長し続けるため崩壊しない設計は必要ですね。仮にディレクトリ名が atoms, selectors だった場合、そのアプリケーションは React と Recoil を使った何かにしか見えないでしょう。

状態管理といえど、主導権はライブラリにあるのではありません。まずはあなたのソフトウェアにきちんと筋を通しましょう。