Reduxアーキテクチャパターンは、JavaScriptのフレームワークReactで広く利用されているパターンです。アプリケーションの状態を一元的に管理することを目的としています。主に以下の3つの要素から構成されています。
Store
- アプリケーション全体の状態(state)を一元的に保持する場所です
- stateは不変のオブジェクトでなければなりません
- getState()でstateを取得し、dispatch(action)でstateを更新します
Action
- stateを更新するための情報の塊です
- type(更新種別)とpayload(更新内容)を含むオブジェクトです
- dispatchによってStoreに送られ、Reducerが処理します
Reducer
- ActionとcurrentStateを受け取り、新しいstateを返す純粋関数です
- Actionに基づいてstateをどのように更新するかを定義します
Reduxの動作の流れは以下の通りです。
- Viewからユーザー操作があると、適切なActionオブジェクトを生成します
- このActionを
dispatch(action)
によってStoreに渡します - StoreのcurrentStateとActionを受け取ったReducerが新しいstateを生成します
- StoreのcurrentStateが書き換わり、Viewに変更が反映されます
具体例として、カウンターアプリを考えてみましょう。
// Action Types
const INCREMENT = 'INCREMENT'
const DECREMENT = 'DECREMENT'
// Action Creators
const increment = () => ({ type: INCREMENT })
const decrement = () => ({ type: DECREMENT })
// Reducer
const counterReducer = (state = 0, action) => {
switch (action.type) {
case INCREMENT:
return state + 1
case DECREMENT:
return state - 1
default:
return state
}
}
// Store
import { createStore } from 'redux'
const store = createStore(counterReducer)
// View
const Counter = ({ value, onIncrement, onDecrement }) =>
<div>
<h1>{value}</h1>
<button onClick={onIncrement}>+</button>
<button onClick={onDecrement}>-</button>
</div>
const render = () => {
ReactDOM.render(
<Counter
value={store.getState()}
onIncrement={() => store.dispatch(increment())}
onDecrement={() => store.dispatch(decrement())}
/>,
document.getElementById('root')
)
}
render()
store.subscribe(render)
この例では、ボタンクリックによりActionCreatorが適切なActionオブジェクトを生成し、dispatchによってStoreに渡されます。CounterReducerがActionの種類に基づいてstateを更新し、Viewに反映されます。
Reduxのメリットは、アプリのstateを一元管理できることで、複雑なステート管理を避けられる点にあります。また、stateの変更ロジックをReducerに集約できるので保守性も高くなります。一方で、アクションの作成、Reducerの実装など、Reduxを使う上での手順がやや煩雑だったり、状態が細かく分割されすぎるとReducerが肥大化する可能性があるなどのデメリットもあります。