reduxを試してみた(1日目) - Reduxをざっくり理解する

  • 175
    Like
  • 0
    Comment
More than 1 year has passed since last update.

React.jsと組み合わせるfluxのライブラリreduxを試してみた。 このページは作業ログです。やったことをつらつら書くだけなのでまとめません。あしからず。

対象読者

  • 主に自分

ゴール

  • 最近のJavaScript開発環境に馴染むこと
  • reduxを使ったアプリケーション開発がどんなものか理解できていること

reduxを試した理由

  • React.jsと組み合わせるfluxの中で最右翼
  • 今作っているSPAアプリがある程度複雑になりそうなのが見えているため
  • (Mithrillくらいシンプルな方が良さそうな気がする)

やったことメモ

node.jsの更新

まずはnodeを更新しようと思い、下記のコマンドを実行。

$ brew update

するとError: uninitialized constant Formulary::HOMEBREW_CORE_FORMULA_REGEX. Please report this bug: ...と表示された。Homebrewのページによると、もう一度brew updateすればいいらしい。

$ brew update
$ brew upgrade node
$ node -v
v0.12.7

開発に必要なツール群のインストール

babelのインストール

$ npm install -g babel

これでbabel-nodeもインストールされた。

webpackのインストール

$ npm install -g webpack

reduxのexampleを動かす

リポジトリのclone

$ git clone git@github.com:rackt/redux.git
$ cd redux

リリース版をcheckout

masterは開発版であることが多く、安定していないかもしれないので、タグを見てリリース版をcheckoutする。githubのリポジトリを見てもよさげ。

$ git tag
$ git checkout v1.0.1

exampleのビルド

JavaScriptだからbuild不要だと思ってたら、ES6で書かれているから変換が必須。bundle.js

$ npm run build
# なにかエラーがあったら「コマンドが足りていない」等なので適宜対応する。

exampleを動かす

$ cd examples
$ ls
async       buildAll.js counter     real-world  testAll.js  todomvc

v1.0.1時点では下記の4つがexampleにて公開されている

  • async : redditから指定したタグのコンテンツを取得し、一覧作成
  • counter : ボタンを押した回数を数えるカウンタ
  • real-world : GitHubの情報を取得して表示
  • todomvc : TodoMVCのredux版の実装

asyncreal-worldはredditやGitHubに接続するので、ネット環境がない場合は動作しない。

ドキュメントを読んでみる

Reduxに関するドキュメントは、racktというReact.jsのコミュニティにドキュメントが公開されている。

平易な英語で書かれているので読みやすい。

Reduxを一言で言うと、予測可能な状態を作るための入れ物(Redux is a predictable state container)だそう。読み進めていくにつれ、確かにそうだと思った。

ところでタイムトラベル(TimeTravel)ってなんぞ? Undo/Redoとか特定の時点での状態を取り出せるってこと?

1.1 動機

ドキュメント

MutationとAsynchronousの2つからくる複雑さを解決するためのライブラリがRedux。アプリケーションが持つ状態はMutableだし、それが非同期(Asynchronous)に変わるからアプリケーションが複雑になりがちだから、作ったらしい。

1.2 3つの原則

ドキュメント

  • 真実は1つ(Single source of truth) : 唯一のstoreオブジェクトにアプリケーション全体の状態を持たせる
  • 状態は読み取り専用(State is read-only) : 状態変更には明確に何が起きるのかわかるactionを使う
  • 状態変更は関数で書く(Mutation are written as pure functions) : 状態のオブジェクトツリーがどう変わるのかを明確に表現するためにreducerを実装する

1.3 既知の技術(Prior Art)

ドキュメント

Reduxを実装する際、参考にした既存技術がまとまっているみたい。

  • Flux : ReduxはFluxの実装ではあるが、Fluxではない。Dispatcherにはコンセプトがないのと、Stateオブジェクトを必ずImmutableになるよう扱うところがFluxとは違うらしい。Fluxよりもシンプルで十分なアーキテクチャに見える。(私見)
  • Elm : ある状態+アクション=次の状態(state, action) => stateというアーキテクチャを推奨した関数型プログラミング言語
  • Immutable : JavaScriptのオブジェクトのデータ構造を永続化するライブラリ。
  • Baobab : 大体同上
  • Rx : リアクティブプログラミング!

2. Reduxの基本

ドキュメント

Redux自体はFluxパターンの実装という位置づけのためReactに依存していない。ビューにEmberでもAngularでもjQueryでもいける、と書かれている。そのため、このドキュメントはReact以外の部分から解説が始まる。

  • Actions : Storeに送るデータ。Fluxとは異なり、副作用を作らないためにJavaScript Objectを返すだけの実装。
  • Reducers : Actionによって起きたイベントからアプリケーションの状態を変更する。アプリケーション全体のスコープで管理するstateオブジェクトを適宜分割して状態を管理するのがRedux way。
  • Store : Storeはアプリケーションの状態の管理とActionが起きた時のイベントを受け取る。イベントを受け取った時に通知するListenerも登録できる。
  • Dataflow :
  • Using with React : ここでReactとの組み合わせを解説

2.1 Actions

ドキュメント

アプリケーションからイベントを受け取り、Storeにデータを送る。イベントの種別毎にtypeを定義する。

2.2 Reducers

ドキュメント

実装順は下記のように考える。

  1. アプリケーション全体の状態オブジェクトを設計する
  2. アクション毎の状態の操作をプロパティ毎に実装する
  3. combinedReducer()でそれぞれのプロパティ毎の操作を行うfunctionをガチャコンする

2.3 Store

ドキュメント

Storeクラスが担う責務は下記の4つ

  • アプリケーションの状態の保持
  • 状態へのアクセッサ : getState()
  • 状態を更新する : dispatch(action)
  • リスナの登録 : subscribe(listener).

Storeの作成createState()の最初の引数はReducerで必須。初期状態があるのであれば、2つ目の引数で受け取る。

StoreオブジェクトがReduxの中心的なオブジェクト。

2.4 Data Frow

ドキュメント

Reduxのアーキテクチャは双方向にデータをやりとりしないことを厳格に採用している。それにより、データのライフサイクルが全て同じようになる。Reduxのライフサイクルは下記の4つ

  1. store.dispatch(action)を呼ぶ
  2. reducerを実行し、stateを更新する
  3. 複数のreducerをまとめたroot reducerを実行し、stateのオブジェクトツリーを更新する
  4. storeは更新されたstateのオブジェクトツリーを保持し、Listenerに通知

2.5 Reactとつなげる

ドキュメント

ReactのComponentとバインディングするモジュールをインストール

$ npm install --save react-redux

SmartとDumbの2種類のコンポーネントがあるが、実装ではあまり意識しない。コンテナはSmartコンポーネント、個々の要素はDumbコンポーネントと考えれば大体OKっぽい。

1日目で学んだこと

  • redux は思ったよりも簡単そう
  • Actionを定義し、Action毎にreducerを定義し、storeを変更していく流れはわかりやすい
  • webpackやReactの方を知らなさすぎる。特にReactでComponentのイベントハンドラからActionを作る流れがわからない
  • reduxのstateの変更をComponentに渡していくあたりがよくわからない
  • reduxのボイラープレートを使って簡単なアプリを組みたい

関連エントリ