Reduxは簡単に全部読める規模のライブラリです。ソースコードを読んでからリファレンスを見たほうが理解しやすかったので紹介します。また、有名なコードを読むことによるJavaScriptの勉強も兼ねています。
今回はReduxの中心であるStoreの作成・初期化とdispatch()
について見ていきます。
対象読者
Reduxを少なくとも1回くらい使ってみた人向けです。
バージョンは、2017-2-22時点でmasterの3f319eb7を見ています。
Store
Reduxはreactなどのview libraryと併用し、状態管理をするライブラリです。アプリの状態を1つにまとめた構造(=Store)に対して、操作(=Action)を割り当てる(Dispatch)することで遷移させます。
Store · Redux
まずは、Storeを作成するcreateStore()
をみていきます。しばらくreducer
以外の引数はundefined
だと思っておきます。そうして、関数定義とエラーチェックを省略すると、実体はこれだけです。dispatch({ type: ActionTypes.INIT })
が気になります。
export default function createStore(reducer, preloadedState, enhancer) {
(エラーチェック)
let currentReducer = reducer
let currentState = preloadedState
let currentListeners = []
let nextListeners = currentListeners
let isDispatching = false
(関数定義)
dispatch({ type: ActionTypes.INIT })
return {
dispatch,
subscribe,
getState,
replaceReducer,
[$$observable]: observable
}
}
dispatch()
は3つのことを行います。currentState
更新、currentListeners
の更新、listener()
の呼び出しです。
dispatch({ type: ActionTypes.INIT })
を呼び出した時点では、listeners
は空の配列です。つまり、currentState
更新しかしません。このdispatch()
によって、Stateの初期化を行います。
今考えている状態はcurrentState = preloadedState
、つまりcurrentState
はundefined
です。currentReducer()
は、createStore
の引数で、ユーザが決めたreducer
なのでした。
function dispatch(action) {
(エラーチェック)
try {
isDispatching = true
currentState = currentReducer(currentState, action)
} finally {
isDispatching = false
}
const listeners = currentListeners = nextListeners
for (let i = 0; i < listeners.length; i++) {
const listener = listeners[i]
listener()
}
return action
}
Reducers
Reducers · Redux
ReducersはRedux利用者が定義する関数で、Storeのdispatch()
でcurrentReducer()
として呼び出されます。
前述のStore初期化のために、渡されたStateがundefined
だった場合、初期値を返す必要があります。また、それ以外のときにActionTypes.INIT
のように自分で定義していないActionが渡された場合は、Stateを変更しないで返す必要があります。
/**
* These are private action types reserved by Redux.
* For any unknown actions, you must return the current state.
* If the current state is undefined, you must return the initial state.
* Do not reference these action types directly in your code.
*/
export const ActionTypes = {
INIT: '@@redux/INIT'
}
サンプルコードなどでは、こんな感じで書いているものが多いようです。
const reducer = (state = initialState, action) => {
switch (action.type) {
case UPDATE:
// update state
return newState;
default:
return state;
}
};
あとがき
Reduxはいろんな機能を実装した便利なソフトウェアというわけではなくて、優れた考え方が支持されたソフトウェアなのだな、と思います。コメントも多いので、JavaScriptの勉強にも向いているのではないでしょうか。見切り発車で「その1」と銘打ってみたので、次回に続く予定です。