Reduxのことをわかりやすく
Reduxイントロ
Reduxとはアプリケーションの状態(state)を管理するためのJSライブラリ。 ではアプリケーションの状態とは具体的に何かというと、いろんな目的で後に使用する情報を保持しておくためのグローバルオブジェクト。
小さな例ではページロード時のローディング表示の管理から、大きな例ではSNSアプリでのユーザー情報や投稿などなど。 何を保持するかは自由だが、格納できるデータはシリアライズできるものでなければいけない。
It is highly recommended that you only put plain serializable objects, arrays, and primitives into your store. It's technically possible to insert non-serializable items into the store, but doing so can break the ability to persist and rehydrate the contents of a store, as well as interfere with time-travel debugging.
Reduxが従うルール
Single source of truth
データを保持するための場所(store)は一箇所のみである。
one app — one store — one state
もちろんコンポーネントごとの各々のstateは存在し、全ての状態をこのStoreで管理する必要はない。
Immutability
stateオブジェクトとそのプロパティを直接修正してはいけない。 その代わり、新しいオブジェクトを作り、再度新しいアプリケーションの状態を計算し、その新しいオブジェクトで上書きして再計算する。 つまり、アップデート前の古い状態オブジェクトには一切の変更が加わらないようにする。
Reduxの3つのビルディングブロック
Store
Storeはアプリケーションの状態(state)を格納しておくところ。 Storeはクラスではなくオブジェクトである。 アプリケーションのstateだけでなく、ファンクションやその他のオブジェクトも含んでいる。
Storeのアップデートに対してイベントをlistenすることができる(subscription)。
Storeはオブジェクトで別名state treeと言及される。どんな深さにもネストすることができる。
Actions
ActionsはプレーンなJSオブジェクトであり、何(What)が起きたのかを表現するが、どのように(How)stateが変わったのかは表現しない。 Storeをアップデートする際に、Storeインスタンスにdispatch (send) するものである。その他はReducerによって扱われる。
Actionオブジェクトではtypeフィールドが必須のものであり、これによってどんなActionがdispatchされるのかが表現され、typeにはexportされた定数が入る。 type以外のフィールドはオプショナルで自由に設定してよい。
Actionの一例
{ type: ADD_NOTE, title: 'Some Title', content: 'This is an action object' }
Action Creators
その他に頻出するのがAction creatorsであり、これはプレーンなJSオブジェクトを返すファンクションである。 Action creatorsはactionにダイナミックデータを挿入するために使われる。
Action creatorsの一例
function addNote(title, content) { return { type: ADD_NOTE, title: title, content: content }; }
Reducers
ActionsがWhatを担うならば、ReducersはHowを担う部分である。 Reducersはpure functionsであり、アプリケーションの新しいstateを再計算をする役割を持つ。
ActionsをStoreにdispatchする際に、ActionsはReducersに渡される。 Reducerは2つの引数を受け取る。一つは前のアプリケーションのstateであり、もう一つはdispatchされたactionである。そして新しいstateを返す。
(previousState, action) => newState
つまり、Reducerはdispatchされたactionのタイプに応じてアプリケーションの新しい状態を再計算する。
実際のアプリケーションではReducerは複雑化することになる。
このためによりシンプルなReducerに細かく分けてから、後にReducerのヘルパーファンクションであるcombineReducers
で合体させる。
メインのReducerはRoot Reducerと呼ばれる。
ReduxでのData flow
ユーザーによってあるイベントがトリガーされてアプリケーションのstateがアップデートされたとする。 そのプロセスでは以下のようなことが起きている。
- ボタンのクリックハンドラファンクションがactionをstoreにdispatchする。
store.dispatch()
メソッド - Reduxがdispatchされたactionをreducerに継承する
- storeがreducerによってreturnされた新しいstateを保存する
- ここまででstoreにsubscribeしたので、書いたファンクションがcallされ、それによってUIが都度アップデートする