Reduxとは?
Reduxは状態を一元管理してくれるやつ。Reactはそもそも状態を管理しやすくなるようにしているので、いつでも使う必要はない。一元管理したくなったら使う。ドキュメントには大量の説明とチュートリアルやサンプルがある。
Reduxの仕組み
Reduxは状態(state)を一つのstoreに保存し一元管理します。createStore()
でstoreがつくれます。createStore()
には引数としてリデューサー(reducer)というのを渡します。
let store = createStore(reducer)
reducerとういのは、各アクションとstateを結びつける関数です。具体的には、現在のstateと、アクションを引数にとり、次のstateを返す関数です。
アクションというのは、stateが変わる要因となるアプリケーション上の挙動です(moneyというstateが100のときに、「お金を10支払った」とういアクションがあれば、moneyは90になるべきです)。具体的には下記のようになります。
{ type: 'PAY_MONEY', price: 10 }
reducerは、アクションが発生した場合に、どのstateをどのように変化させるかを規定する関数です。また、reducerには、stateの初期値も登録します。
const iniState = {
money: 100
}
function reducer(state = iniState, action) {
switch(action.type) {
case 'PAY_MONEY':
return Object.assign({}, state, {
money: state.money - action.price
})
default:
return state
}
}
このreducerをstoreに渡すことで、storeは、全てのstateとその初期値と、発生しうるアクションと、アクションがあった場合のstateの変化のさせ方を知ります。
状態の取得や、状態の変化のさせ方は、それぞれstoreに対して、store.subscribe()
と、store.dispatch()
を使います。
store.subscribe()
は、アクションがディスパッチされたときに呼び出される関数です。store.subscribe()
の中で、store.getState()
を使うことで、現状のstateを取得できます。store.subscribe()の戻り値は、subscribeの解除関数です。
store.subscribe(() => console.log(store.getState()))
store.dispatch()
は状態を変化させたいときに使い、引数にアクションを渡します。
store.dispatch({ type: 'PAY_MONEY', price: 10 })
実際には、dispacthの引数に直接アクションオブジェクトを渡すのではなく、アクションクリエーター関数を渡します。アクションクリエータ関数は下記のようになります。
function payMoney(price) {
return { type: 'PAY_MONEY', price }
}
Reduxの簡単な例
import { createStore } from 'redux'
//アクションクリエーター
function payMoney(price) {
return { type: 'PAY_MONEY', price }
}
//Reducer
const iniState = {
money: 100
}
function reducer(state = iniState, action) {
switch(action.type) {
case 'PAY_MONEY':
return Object.assign({}, state, {
money: state.money - action.price
})
default:
return state
}
}
//storeを作成
let store = createStore(reducer)
//subscribe登録
let currentPrice = iniState.money
let unsubscribe = store.subscribe(() => {
let prevPrice = currentPrice
currentPrice = store.getState().money
if(prevPrice !== currentPrice) {
console.log('changed', prevPrice, 'to', currentPrice)
} else {
console.log('no change')
}
})
//actionをdispatchする
console.log('start pay money')
store.dispatch(payMoney(10)) //100 to 90
store.dispatch(payMoney(20)) //90 to 70
store.dispatch(payMoney(0)) //no change
store.dispatch(payMoney(40)) //70 to 30
let hoge = { type: 'hoge', hoge: 'hoge' }
store.dispatch(hoge) //no change
store.dispatch(payMoney(10)) //30 to 20
//subscribeを解除
unsubscribe()
console.log('unsubscribed')
store.dispatch(payMoney(10)) //何も表示されない
console.log('finish pay money')