初めに
React、Draft.js、formikを使って記事編集機能を作った際に、途中からReduxを導入しました。ユニークな記事要素などの状態管理が複雑化したためです。
ちょうどHooksなどReact自体が新機能を発表した直後ではありますが、忘備録ということで。
Reduxを導入し、状態管理について素人ながらにも考えたことなどを書いてみました。
What to store, what not to store
ReduxのStoreでどこまで状態管理するか、という問題はどうやらいろいろ議論・持論があるようです。
公式ドキュメントにもあるとおり、Reduxの責任範囲についての模範解答はありません。
チームやアプリケーションによってそれぞれっぽいですね。
結論からいうと、自分は全ての状態管理をReduxに任せる必要はないと思っています。
全てのコンポーネントの全ての状態をredux storeにて管理することはもちろん可能です。ですが、あるコンポーネント内でしか価値のない状態をreduxを通して統一化するのは不必要ともいえます。
たとえばフォームの入力状態などがそれです。ミクロな変更を毎度storeで管理する必要はありません。これらはコンポーネント内で完結していいstateです。
確かにlocal stateとredux storeが混ざっているのは気持ちが悪い。
その点でformikは綺麗にフォームの状態管理を勝手にしてくれるので、本記事の考え方においてのreduxとの相性がいいと思います。
あらためて判断基準としては、
- コンポーネント外でも利用・参照価値がある情報はredux storeで管理する
- それ以外の、ミクロな他コンポーネントでの利用価値がない情報はコンポーネント内のlocal stateとして完結させる
という方向でいいかと感じています。
ロジックの管理
ビジネスロジックがあちこちのコンポーネントに遍在しているのはあまり好ましくありません。
これを解消するべく存在しているのがContainer Component vs. Representational Componentの概念です。
端的にいうとビジネスロジックとDOMマークアップをコンポーネントとして切り分けて管理しよう、みたいな考え方です。
Presentational and Container Components - Dan Abramov
状態管理ライブラリを導入していない段階では特に、このコンセプトはいまだ有用です。hogeComponent
とhogeComponentContainer
のセットで、UI・UXをいじるときは前者、
ロジックをいじるときは後者、のように切り分けられて、ひとつのコンポーネントがfatになっていくのをある程度抑えることができます。
Reduxとformikを共存させると、ほとんどのロジックがその2つに集約されます。HOCとしてラップさせると、
自然とContainerとRepresentationalを自前に切り分ける必要がなくなり、
コンポーネントはほぼfunctional componentとなっていき、いわゆる"dumb"なものに抑えることができます。
ちょっとつまったジレンマ
全ての状態をstore管理する必要はないと言ったものの、これを貫徹しようとするとちょくちょく問題が出てきます。
例えばAPIリクエストなど、重要なアクションを上記の通りredux storeで管理する場合、
ローカルなフォーム入力などに関する情報であったとしても、必然的にその結果の状態(レスポンス)もredux storeで管理する必要性が出てきます。
このような境地に立った場合、
- 重要なロジックをできるだけreduxにて集約して管理するとし、functional componentになっていくことを副産物として、振り切る
- コンポーネント内外の状態の価値を重視してAPIリクエストのロジックもコンポーネント内に置く。副次的にclass componentとなる。
の二択になるとおもいます。
これは良し悪しは特になく、その時の開発リソースなどと相談するべきでしょう。既存のclass componentでこのような問題になった場合、取る選択肢は後者でもいい気はします。
ただ一見極端に見える前者に振り切ったほうが、外からは思想が一貫されているように見え、わかりやすいとも言えるかもしれません。
まとめ
reduxでの状態管理や、新しく追加されたSuspenseやHooksなど、状態管理のエコシステムはますます複雑化していきそうです。
可読性などを考えると一貫したポリシーをおきたくもなりますが、手段が目的化しない程度に引き続き考えていきたいと思います。