ContextからReduxへ移すに辺り、ReduxのState設計について調べた内容のまとめ

この記事は、Reduxのstate設計について調べた内容になります。

背景として、自分の携わっているサービスにて、ContextAPIを使ってグローバルステートを管理していた。 が、サービスのグロースにてデータ構造的に無理が生じ始めたので、State整理に伴って、これを機にReduxへの切り替えを行った。 そのときに、調べたことをまとめる。

公式ドキュメントを調べる

cover-1-public

何はともあれ、公式のドキュメントを調べる。ドキュメントを呼んだ結果をだいたいまとめた。

公式Doc: Normalizing State Shape · Redux

  • データは正規化させる。

    • データ構造をネストさせない。
    • IDで参照させる。
    • リストよりも、オブジェクトでID参照させる。
  • グルーピングして正規化させる

    • Storeを、/entites、/ui、/domain、で分割する
    • 公式Docだと、文章がメインで具体例が少なすぎてわかりにくいが、「それぞれにどんな役割か?」は、後述の「スタートアップテック」さんのスライドがわかりやすかった。
  • 正規化にてデータ群を、リストからIDをKeyにしたオブジェクトに変換させる。

// Userを例に正規化
// 正規化前
[
  {id: qwer, name: tanaka},
  {id: asdf, name: sato  },
]

// 正規化後
{
  qwer: {
    id: qwer,
    name: tanaka
  },
  asdf: {
    id: asdf,
    name: sato
  },
  allIDs: ['qwer', 'asdf']
  ...
}

公式Doc: Basic Reducer Structure · Redux

  • Domain, App, UI の3つのStateに大きく分ける。

    • Domain: entites的なやつ。 Rawなデータ
    • App: アプリの振る舞いに依存するもの。SelectedやLoadingなど。
    • UI: Presentetional層で表示に特化したもの。
  • 「stareの形」のことをshapeと呼ぶ。
  • 「スライス」=「Storeにおけるサブツリー」のこと。

State設計にまつわる記事を読む

cover-2-private

他にも記事をいろいろ探して読んでみた。

スライド: reduxのstate設計の話 - スタートアップテック

  • DomainStateとUIStateでStateを分ける(画面かドメイン)。それぞれの分け方でメリデメがあるので整理。
  • 大きく、/entites、/domains、/uiの3つのツリーの種類に分けてる。
  • entitesへの正規化では、idをkeyにしたオブジェクト化をしてる。またリレーションデータは実データではなくて、リレーショナルにIDで参照。

スライド: ReduxのState設計のお話 - Retty

  • APIのReponseとStateとの観点で、Stateを考える話。
  • シンプルなアプリなら [Responseデータ] -> [State] でよいが、複雑なアプリ・データでは愚直に1vs1対応をすると非正規化が発生する。
  • RDS的にデータを保持させるのがベターとの判断。
  • 「Element層」というのを作ってAPIの変化に対応。[API] → |FRONTEND| → [Response] → [Element] → [View]

Redux Architecture Guidelinesを読んでの所感

  • redux/action設計についての基本的な考え。
  • オブジェクトの入れ子を避ける
  • UI用データをStateに保存しないで、Rawデータを入れる

Twitter公式サイトのRedux Store設計を少しだけ読み解いてみる

  • TwitterのState設計を見て、設計を考察。
  • normalizerというライブラリでResを正規化。https://github.com/paularmstrong/normalizr
  • /entitesの配下にてResponseRawデータ管理。
  • /entities配下にて、loading管理をしている。

Dissecting Twitter’s Redux Store - Statuscode - Medium

  • /entities/tweets/entities に、1つ1つのツイートのRawデータ
  • /homeTimelines/timeline に、タイムラインのデータを格納

React/Reduxの設計に関する参考記事まとめ - dackdive's blog

  • この記事みたいなの。自分が見つけられなかった記事がいろいろあったので、助かった。

あとがき

cover-last

まとめ

  • 正規化をする。リストからオブジェクトにしてアクセッサビリティを担保する。DRYを重視して、リレーショナルに設計する
  • 公式ではloadingステートはAppStateだが、TwitterではEntities配下にあったりするので、ベストプラクティスがまだ確立されてないようにも思える。ある程度は選択して決める

所管

ContextからReduxへのリプレイスでState周りを色々調べたが、「そもそもContextでのState設計をよりきちんと行えればReduxへのリプレイスせずとも良かったのでは?」というのが一通り開発が終わってからの印象。

  • ReduxWayを進める派
  • ContextWayを進める派

ReduxWayによるState設計は、ひとまずのベストプラクティスが確立されているように思える。が、ReactHooksについては、登場したばかりで情報が少ないので、設計指針がわからなかった。

「ローカルで表現できるものはuseStateで、グローバルにしないと表現が厳しいものはContextに、」を指針に、でサービスのグロースに伴って増築を繰り返したら、Contextがゴチャツキ出していたので、そのタイミングでReduxへのリプレイスを行ったが、そうではなくContextのStateを再設計・整理するべきだったのかもしれない。それこそ、Reduxみたいにentities・domains・uiみたいに責務を分割させたり?とか。

とはいえ、Reduxにする選択をしても、今ではreact-reduxにuseDispatch / useSelectorがあるのでconnect/mapStateToProps/ mapDispatchToPropsが必要なく、記述量もだいぶ少なく済む。

枯れた技術のReduxか、新しい技術のHooksか、でメリデメがあるので、どう設計するのか?はある程度は決めの問題もありそうかな、という印象でした。

機会があれば次はContextによるState設計について調べたいですね。

Nash
Nash

プログラミングが好きな人。SE→ITベンチャー→フリーランス。日本を出て、海外で働いて、最終ゴールは月で生活すること。