Redux
#状態管理(GUI) #Flux #宣言的UIの設計レシピ #アーキテクチャ
The Elm Architectureを源流とし、Fluxをリファレンス実装したライブラリ
https://redux.js.org/style-guide/
静的関数型由来の概念が多く、opinionatedでスタイルガイドが豊富
学習ハードルは割と高いが、その理論は完成されている
https://slides.com/jenyaterpil/redux-from-twitter-hype-to-production#/27
https://scrapbox.io/files/64407e7f70debf001c2bc99b.png
人によっては以下でも雰囲気が伝わるかもしれない
Stateモナド
Effect System
CQRS
Dan Abramov自身の解説
https://egghead.io/lessons/react-redux-react-counter-example
宣言的UIと歴史的な背景から分かる
脱MVCを目指して生まれた
フロントエンドでMV*フレームワークを使わない理由
理論的な話
2015年頃の記事を読むと時代背景がわかりやすい
Redux入門【ダイジェスト版】10分で理解するReduxの基礎
/mrsekut-p/Reduxのアーキテクチャパターンの話
/miyamonz/middleware パターンに対する考察
Reduxで実現されていることはなんなのか
「純粋関数適用以外での値の変更を許さない」ことを強制することによって、「処理の途中で不規則なデータ変更によって生じるバグを未然に防ぎ」、変更に冪等性があることから、「バグが発生した時に、どの順序で何の処理を行ったかという履歴を追跡することで、バグ発生時の状況を必ず再現できること、また、何を行ったことでバグが発生したのかを追跡する」こと
/fsubal/Redux「GET リクエストは更新系」
Redux における「参照系(があるとしたら)」とは Selector、旧くは react-redux における mapStateToProps だけを指す。action は常に更新系、CQRS の C だという発想がないと設計で混乱すると思う。
逆に言うと Redux を選択するっていうことはこの思想を受け入れるってことでもあるので、Read がメインで状態の更新が少ないケースでは、複雑度に関係なく選ばないほうが良いと思う。
実践的な話 #CQS #CQRS
reduxでビジネスロジックをゴリゴリ書く
reduxをCQRSとして捉える
reduxをevent sourcingとして捉える
actionの無限長配列に対してreducerし続けることで現在のstateを表現するステートマシン
Domain Driven reDux - or Redux as CQRS
ReduxはただのクライアントサイドCQRSだよ
CとQをドメインごとに切ると捗るよ
けど純粋な ducks パターンはきついよ
ドメインモデルはプレーンなjsonと純粋関数で持つと良いよ
Redux の利点を振り返る
Redux 再考
難しさが廃されるのではなく、難しい部分が一箇所に集中する。React Component の末端では、何も考えることがなくなる。状態管理という難しい部分を作る人と、末端のコンポーネントのデザインに注力する人を分けられる。
大規模になっても設計が破綻しにくい、というエンタープライズ向きな特性を持つ。が、その技術基盤は(静的)関数型由来の考えが多く、基礎設計や基盤理解にはハイスキルが要求され、需要と適用対象のミスマッチを感じることはある。結果として、そもそもハイスキルを前提として、大規模であることが自明な SPA 向きということになる
redux の作者でありオピニオンリーダーだった Dan Abramov は、現在 redux との距離を置いているように見える。React コアチームに近い、よりシンプルなものを、という立場になっている
/fsubal/Reducer を REST のリソース単位で分割する
なんだかんだで Redux は「(REST) API から取ったモデルを View Model にする」というパラダイムの産物だと思う。
クライアントサイドの状態設計をする際は、常に「このモデルは親になることがありうるか?」「親から独立してそれ単体で一覧や詳細を取得するシチュエーションがあるか?」を自問するとよい。それがありうるモデルだけを reducer の主語にすると上手くユースケースに応じてまとまりやすい。「こいつは他のモデルのサブリソース以外にならないんじゃないか?」と思ったら json の 1 プロパティにとどめた方がよく、それは API 側も大抵そうなっているはずだ。
React / Redux を実務で使うということは
/tosuke-diary/React / Redux を実務で使うということは
「React / Redux を実務で使うということは」を読んで思ったこと
令和にはじめるReduxの学び方
2019年ごろからReact Hooks, Suspenseが登場してからは第一線を引き始めた
コンポーネントのView ModelはReact Hooksで事足りる
非同期処理もSuspenseで冪等に出来る
/terrierscript/2020年になったのでRedux離れを考える
/miyamonz/redux不要論
/fsubal/Flux の失敗は Store に Store という名前をつけたこと
軽く使うには、Reduxって結構色々知らなきゃいけなかったりしますよね
React HooksとTypeScriptを使ったRedux再実装で理解度を深める試みしましょう
React > ContextとuseReducerは大体はReduxの車輪の再発明になる
React > Context#640fccae866030000031fdbd
koushisa.icon
フロントエンドの状態管理にCQSのエッセンスで純粋性を持ち込んだ先駆者
GUIの時系列で変化する状態を副作用のないImmutable Modelで表現するパラダイムの礎を築いた
Streamといった難しい概念を意識しなくて良い
イベント駆動による疎結合も含め、アーキテクチャとして完成されている
スタイルガイドやその思想の普及、議論してきた人たちも含め大いにリスペクトしている
ReduxとAlmin.jsから学んだレイヤリングと関数型由来のアプローチ(CQS,Action,Reducer)の考え方はずっと生きてる
Reduxの本質
Redux の本質は 状態遷移の純粋関数化 (Reducer) と、それに伴う 合成容易性 にあると考えています。
遅延結合と遅延初期化とリソース更新/破棄の自動化できる
コンポーネントはActionのことだけを考えていれば良い
「それがなにか」(What)と「どうするか」(How)の分離
イベント(Action)と状態遷移Reducerを分離して考えられる
分業に適している
→決断を遅らせる
Action→Reducerを通る時の副作用をミドルウェアに投げられる
エラーハンドリング, ロギング, 通知などの横断的な関心事はPub/Subアーキテクチャで疎結合にできる
余分なコードを書かずにイベント駆動な単方向データフロー(unidirectional data flow)を構築できる
参照透過性のあるReducerをスニペットとして使い回せる
合成容易性, テスト容易性が非常に高い
更新を集約(Aggregate)単位で実施することをアーキテクチャレベルで強制する
単方向データフロー(unidirectional data flow)による制御の反転(IoC)
Reduxの問題点
Redux関係ツールは大量のoverloadとgenericsを駆使して型付けされているので、コンパイルエラーが絶望的にわかりにくい
メッセージパッシングによるデータフェッチはトランザクションが生じる手続き的な処理と相性が悪い
副作用起こすなら戻り値返すな
戻り値返すなら副作用起こすな
例えば、ローディングの状態管理はコンポーネントのライフサイクルと密結合なので手続き的に制御するほうが都合が良かったりする
データフェッチするのにLOADED, LOADINGなどのActionを複数回実行するのがメンタルモデルと乖離しがち
thunkやsagaなどのミドルウェアで頑張っていたが、コード量が多すぎて直感的ではなかった
あと、データフェッチにおいてonSuccess、onError、onSettledはアンチパターン
単なるデータフェッチのキャッシュ用途としてのストアになっていた
@yuta0801_: ただ普通のアプリケーションだとAPIから取ってきたデータをキャッシュに保存するだけで、CRUD以外のアクションがほとんどないという…
normalizrで正規化もしたりしてた
ActionもSelectorも盛りだくさんで、目が滑る
ここが水漏れ, 割れ窓だった
キャッシュ管理については現在はより筋のいい方法が見つかった
後述
ドメインモデルの記述場所がなかった
@seanchas_t: React、ドメイン→UIのマップを宣言的にできるようにしただけで、ドメイン自体の管理にはOOPが必須だと思ってる
#オブジェクト指向
#尋ねるな、命じろ_(Tell,_Don't_Ask)
RxやMobXでみんな頑張ってた
ここを解決するためにAlmin.jsが生まれた
Action, Reducerの設計統一の難しさ
宣言的UIの振る舞いを分割する単位はページなのか機能なのか
分割しようとすると大量のAction, Reducerが必要になるし設計難易度が高まる
同じ時間軸で別のReducerを同時に更新したい場合はどうする?
Form State, Server State, Navigation Stateもストアに入っていないと組み立てられない
ほぼ全てのステートをReduxに乗せて運用するレベルの覚悟が必要
コンポーネントのprops制御で完結できるものも含めて全てのロジックをReduxに乗せる
アコーディオン開閉状態みたいな本質的にはUI Stateに分類できるものまで紛れ込んでくる
分割しないとfat model化
一つのreducerに複数の責務が入ってくる #責務が肥大化
どこで何が起きてるかわからなくなり、無法地帯になっていく
疎結合であるが故に追うのも難しく、コードを削除するのが恐くなる
ストアとコンポーネントの結合度が高まっていく
分割すればするほどdispatchは複雑になる
複数のdispatchを組み合わせるレイヤが必要になる。 集約(Aggregate)的な
丁寧に制御しないとレイヤ横断実装が発生する
境界づけられたコンテキスト, 契約による設計のような勘所
求められる知識量と経験が指数関数的に増えていく
ジュニアエンジニアや新規の参画者にとっては優しくない
学習教材や知名度による人的資本のスケール容易性を損なう
一応、経験者が先導して引っ張っていけばなんとかなるものではなる
相応のリソースは取られる
目的置換も発生しやすい
リーダーがレビューで死ぬ
コメントしたら進まなくなるし今回はやめておこう
限られた時間は「開発者のための設計統一」より「ユーザーにとっての価値最大化」に割きたい
多様性や負債を排除せずに受け入れる
ジレンマが重なり、やりたいことに対し不必要に複雑な構成になっていく
特定のライブラリをReduxで使えるようにするためのAdapterみたいなのも必要になる
そもそもSPAは「クライアント」なので「サーバー」のリソースを変化させる副作用や非同期処理が主である
状態遷移を疎結合にする旨味よりも、冗長性や全体像を掴みづらいデメリットのほうが高くつく
一般的なアプリケーションではReduxはオーバーキルだった
動作上は問題ないはずなのに型定義的な問題からコンパイルが通らない
作りたいものに対して世の中の技術スタックは複雑になりすぎている
たとえReduxを使ったとしてもフロントエンドの本質的な難しさは解決できていない
SLAP原則#63eaa2eb8660300000643823
コードとしての複雑さがあるときにトップダウンで分割すると、本質的な難しさは解決せず隠蔽されているだけのことが多いように思う
フロントエンドの複雑性
これらの問題点に対するReduxの作者(Dan Abramov)が直々に声明を発表
You Might Not Need Redux
これが決定的となり、React Hooksの登場でパラダイムシフトが起こった
React HooksとRender As You Fetchパターン
React Hooksを活用したデータフェッチのSimpleな解決策
ここからボトムアップに状態管理する方法が主流になった
(koushisa.iconはあまり好きではないが)RTK Queryも登場した
Fluxの反省点を踏まえて技術の螺旋が一周したと捉えている
SSoT(唯一の情報源)を活かしつつレンダリング制御の処理はコンポーネントツリーにまとめられる
コンポーネントの純粋性が高まってより高凝集になった
ここにうまく適応できた TanStack Queryがデータフェッチであっという間に覇権をとった
宣言的UIのデータアーキテクチャはコンポーネントを中心に考える#632a3eab8660300000c4af1b
HTTPリクエストのロード状態なんか
const { loading } = useQuery(...);
で今どきは済むところをusecase->port->presenterとかやる意味ンゴ…😇
「SPAで管理する必要のあるGlobal Stateって、そのうちほとんどがサーバーデータのキャッシュだよね。それを取り除けたら、管理する必要のあるGlobal Stateってすごく小さくなるんじゃない?」という主張を私が認識しはじめたのが2020年の初旬でした。
hooks APIで整理することでReduxが不要に。
/teramotodaiki/useSWRに出会うまでは、fetchの回数をなるべく減らしたいと思っていた#6326ab11b90429000079b66b
Fluxの思想は5年経った今(2023)でも有用
「FacebookはReduxは使っていないがFluxは使っている」と昔だれかが言ってた(覚えていない)
単方向データフロー(unidirectional data flow)
関数型プログラミングのアプローチ
Immutable Modelによるユニオン型(union type)を生かしたパターンマッチング
これらの総称であるメッセージパッシングとしてのオブジェクト指向が本質だった
Immutable ModelはAtomic State Managementへ引き継がれた
中央集権から脱却した分散型のボトムアップ方式
GUIプログラミングにおけるActionとReducerの関係性をコードで示す
そして2023年
React Server Componentsが生まれた
新しい方法論の提示
React は人類が直接コーディングする最後の UI ライブラリになる#640a63d28660300000927429
5年後ぐらいにこの文脈で、コンポーネントの遅延束縛手段として再登場するんじゃないかと期待している
イベント駆動と単方向データフロー(unidirectional data flow)によるコンポーネントの独立化