まえがき
ReactでState管理がしたくなったのでReduxを導入することにしました。
Qiitaの記事だけだと理解が難しかったので、チュートリアルをちゃんとやって勉強しました。
この記事はRedux単体のものです。
React+Reduxに関してはこちら
Reduxとは何だ?
Reduxは状態管理コンテナです。
Reactとセットで語られるのをよく聞きますが、これ単体で機能するパッケージです。
ある程度の規模のソフトウェアを書いたことがある人は状態管理の難しさはよく分かるものと思います。
ReduxはState(状態) を 以下の部品を使っていい感じに管理します。
- Action
- Reducer
- Store
Stateの定義
State(状態)の表現方法は様々です。
Reduxにおいてはアプリケーション内の全での状態を1つのオブジェクトに格納するという考え方をします。
TODOリストのサンプルコードをみるとわかりやすいと思います。
入れ子になった木構造をイメージしてください。
{
visibilityFilter: 'SHOW_ALL',
todos: [
{
text: 'Consider using Redux',
completed: true
},
{
text: 'Keep all state in a single tree',
completed: false
}
]
}
Stateの管理
主要な流れです。
Actionの内容に応じてReducerがStateを変化させる仕組みです。
StoreがStateとReducer、その他諸々をパッケージしていい感じにオブジェクト指向にしてくれています。
要するにステートマシンを簡単に実装する機構だと思えばわかりやすいかもしれません。
Action
ActionはStateに変更をもたらす通知データです。
Storeにdispatchすること適用することができます。
ここが大事なのですが、フォーマットが決まっています。
- PlainObjectである必要がある。1
- キーに
type
が存在する必要がある -
type
の値は文字列推奨
{
type: 'some string'
...
}
端的に言うとtype
ラベルが付いた軽量なオブジェクトを用意しろということです。
Reducer
ReducerはStateに変更をもたらす処理です。
ActionとStateを読み込んで次のStateを出力する関数を定義します。
こちらもやはり、関数仕様が決まっています。
- アプリケーション全体で一つだけ定義する
- 純粋関数である2
- 引数がActionと現在State
- 返り値が更新State
- 非サポートのアクションはstate変化を変えないことが推奨
function todoApp(state = initialState, action) {
switch (action.type) {
case SET_VISIBILITY_FILTER:
return Object.assign({}, state, {
visibilityFilter: action.filter
})
default:
return state
}
}
特に純粋関数で有ることは極めて重要です。
ここでAPI呼び出したり、内部状態を読み書きしたりしたら状態管理もなにもないので、実装するときは特に気をつけないといけないところです。
初期Stateもここで定義できます。
Store
ReducerとStateをまとめてインターフェイスを提供します。
提供するインターフェイスは以下
メソッド | 役割 |
---|---|
getState() | Stateを取得する |
dispatch(action) | Stateを更新する |
subscribe(listener) | State変更時のコールバックを登録する |
作成には専用の関数使用します。
このときにも初期Stateを設定することができます。
import { createStore } from 'redux'
import todoApp from './reducers'
const store = createStore(todoApp)
補助要素
ActionCreator
Actionを生成する関数の総称です。
書くとわかりますが、ActionはPlainObjectである必要があるので作るのが結構手間です。
アプリケーションのオブジェクトからActionを作るのが主な用途と思われます。
Splitting Reducer
Reducer自体はアプリケーション全体でひとつなのですが処理の一部を切り出して小さいReducerを作る事ができます。
これはActionの特定のtype
がStateの特定の子要素にのみ作用するときに有効です。(そしてそうなるように設計するのが望ましい)
そうやって子Reducerに処理を委譲していくと根Reducerは子Reducerに処理を移譲して結果をつなぐだけになります。
そういう場合にcombineReducers
という関数を使えば省略して表現することができます。
サンプルコードで結構目にする関数なのでギョッとしますがReducerを合成しているだけです。
まとめ
- Reduxは状態管理コンテナ
- Actionを受け取ってReducerがStateを変化させる
- ReducerとStateをパックしてインターフェイスを提供しているのがStore