まとめ
- createStore => store objectを返す。
- dispatch => reducerを実行して新しいstateを作る。stateが変化した時に実行する処理(listener)を実行する。
- subscribe => stateが変化した時に実行する処理(listener)を登録する。
- replaceReducer => reducerを入れ替える
- observable => subscribe時に実行した処理を登録する
Redux
Fluxを実装した一番人気のあるフレームワーク。
開発者がReact Core Teamでも一番熱心に活動している人のようなので安心して使える。
Facebookのアプリでも使用されていたので公式に推奨されているように感じる。
Store
Reduxのメインとなる機能。
createStoreで作成される。
https://github.com/reactjs/redux/blob/master/src/createStore.js
- reducer
- initialState
- enhancer
これら3つを引数として作成される
export default function createStore(reducer, initialState, enhancer) {
...,
if (typeof enhancer !== 'undefined') {
...,
return enhancer(createStore)(reducer, initialState)
}
var currentReducer = reducer
var currentState = initialState
...,
}
この通り、enhancerはcreateStoreを引数にとって新しいcreateStoreを生成するようなfunctionであることがわかる。wrapperに近い?
ここからcurrentReducerとcurrentStateがreducerとstateに置き換わる。
export default function createStore(reducer, initialState, enhancer) {
...,
return {
dispatch,
subscribe,
getState,
replaceReducer,
[$$observable]: observable
}
}
上記より、各methodが入ったObjectがstoreということがわかる。
...,
function dispatch(action) {
...,
try {
isDispatching = true
currentState = currentReducer(currentState, action)
} finally {
isDispatching = false
}
var listeners = currentListeners = nextListeners
for (var i = 0; i < listeners.length; i++) {
listeners[i]()
}
return action
}
...,
ここからreducerはstateとactionを引数にとり、新しいstateを返すようなfunctionであることがわかる。
listenerは何かというと、subscriptionされているfunctionであることがわかる。
...,
function subscribe(listener) {
if (typeof listener !== 'function') {
throw new Error('Expected listener to be a function.')
}
var isSubscribed = true
ensureCanMutateNextListeners()
nextListeners.push(listener)
return function unsubscribe() {
if (!isSubscribed) {
return
}
isSubscribed = false
ensureCanMutateNextListeners()
var index = nextListeners.indexOf(listener)
nextListeners.splice(index, 1)
}
}
...,
返り値を保持することで登録したlistenerをunsubscribeすることが可能。
このような返り値で登録したものを削除する処理はReact界隈ではよく見るので、覚えていて損はなさそう。
...,
function replaceReducer(nextReducer) {
if (typeof nextReducer !== 'function') {
throw new Error('Expected the nextReducer to be a function.')
}
currentReducer = nextReducer
dispatch({ type: ActionTypes.INIT })
}
...,
名前の通り、reducerを入れ替える処理。入れ替え時に、INITのActionが走る。
大体の実装ではswicthのdefaultケースを返す感じかな。
...,
function observable() {
var outerSubscribe = subscribe
return {
subscribe(observer) {
if (typeof observer !== 'object') {
throw new TypeError('Expected the observer to be an object.')
}
function observeState() {
if (observer.next) {
observer.next(getState())
}
}
observeState()
var unsubscribe = outerSubscribe(observeState)
return { unsubscribe }
},
[$$observable]() {
return this
}
}
}
観測用にsubscribeしています。
普通にsubscribeするのと何が違うのかは登録時に、observerが実行されることくらい。
最後に
言語の状態を変更するreducerと、各componentのsetStateを登録して全部のコンテンツを変換するようなものが簡単に出来そうな気がしました。
middleware, combineReducers編に続く・・・(完)