ReduxのGithubドキュメントを基に入門用記事として書いたものを、簡潔にまとめました。
もと記事はこちらです。
- Redux入門 1日目 Reduxとは
- Redux入門 2日目 Reduxの基本・Actions
- Redux入門 3日目 Reduxの基本・Reducers
- Redux入門 4日目 Reduxの基本・Stores
- Redux入門 5日目 Reduxの基本・Data Flow
- Redux入門 6日目 ReduxとReactの連携
Reduxとは
Reduxは、ReactJSが扱うUIのstate(状態)を管理をするためのフレームワークです。Reactではstateの管理するデータフローにFluxを提案していますが、ReduxはFluxの概念を拡張してより扱いやすく設計されています。
Reduxはstateを管理するためのライブラリーなので、React以外にもAngularJSやjQueryなどと併せて使用することもできますが、Reactと使用するのが一番相性がいいです。
Reduxの要素
Reduxの要素と、それらの相関図です。
- Action
- ActionCreator
- Store
- State
- Reducer
Todoアプリを例にしてReduxのデータフローをたどりながら、これらの要素を説明していきます。
###1. ユーザーの入力から、アクションを作成する
ユーザーがtodoのテキストを入力して追加ボタンを押した場合を想定します。
ActionCreatorのメソッドに入力内容が渡されて、Actionのオブジェクトを作成されます。
Action
Actionは「何をする」という情報を持ったオブジェクトです。Actionはtypeプロパティを必ず持つ必要があります。
{
type: 'ADD_TODO',
text: 'Build my first Redux app'
}
ActionCreator
ActionCreatorはActionを作成するメソッドです。
FluxのActionCreatorとは違い、Actionを作るのみを行いStoreへのdispatchは行ないません。
function addTodo(text) {
return {
type: ADD_TODO,
text
}
}
2. StoreへActionをdispatchする
ActionCreatorで生成されたActionをStoreに送ります。
Storeのインスタンスにdispatch(action)を行なう事でStoreへ変更を伝えます。
dispatch(addTodo(text))
Store
Storeはアプリケーションの状態(state)を保持している場所です。
Storeはアプリケーション内で一つ存在し、一つのstateを保持しています。
Storesの役割は、
- stateを保持する
- stateへアクセスするためのgetState()を提供する
- stateを更新するためのdispatch(action)を提供する
- リスナーを登録するためのsubscribe(listener)を提供する
State
アプリケーションでの状態を表します。
このTodoアプリでは「現在選択されている表示/非表示」、「todoのリスト」をstateとして保持します。
より内容が複雑になる場合は、ネストしたツリー状の構造で表します。
{
visibilityFilter: 'SHOW_ALL',
todos: [
{
text: 'Consider using Redux',
completed: true,
},
{
text: 'Keep all state in a single tree',
completed: false
}
]
}
###3. dispatchされたactionとstateをReducerへ渡す
Storeは、Storeを作成する際にStateを変更するためのメソッドであるReducerを一つ登録します。
Storeはdispatchされると、引数のactionと現在保持しているStateをReducerへ渡し、新しいStateを作成します。
import { createStore } from 'redux'
import todoApp from './reducers'
let store = createStore(todoApp)
Reducer
reducerはactionとstateから、新しいstateを作成して返すメソッドです。ポイントは、引数のstateを更新することはせず、新しいstateのオブジェクトを作成して返します。
reducerのメソッドは副作用を起こさないpureな関数でなければならず、Aというstateに対して毎回必ずBというstateを返すような関数でなければなりません。
Reducerの実装は、actionのtypeに応じて処理を書く事になります。
function todoApp(state = initialState, action) {
switch (action.type) {
case SET_VISIBILITY_FILTER:
return Object.assign({}, state, {
visibilityFilter: action.filter
})
case ADD_TODO:
return Object.assign({}, state, {
todos: [
...state.todos,
{
text: action.text,
completed: false
}
]
})
case COMPLETE_TODO:
return Object.assign({}, state, {
todos: [
...state.todos.slice(0, action.index),
Object.assign({}, state.todos[action.index],{
completed: true
}),
...state.todos.slice(action.index + 1)
]
})
default:
return state
}
}
Reducerはアプリケーションが大きくなるにつれて実装が肥大化してしまうので、Reducer内に子Reducerを作成し、stateのプロパティごとに子Reducerで処理するようにします。
function todos(state = [], action) {
switch (action.type) {
case ADD_TODO:
return [
...state,
{
text: action.text,
completed: false
}
]
case COMPLETE_TODO:
return [
...state.slice(0, action.index),
Object.assign({}, state[action.index], {
completed: true
}),
...state.slice(action.index + 1)
]
default:
return state
}
}
function visibilityFilter(state = SHOW_ALL, action) {
switch (action.type) {
case SET_VISIBILITY_FILTER:
return action.filter
default:
return state
}
}
function todoApp(state = {}, action) {
return {
visibilityFilter: visibilityFilter(state.visibilityFilter, action),
todos: todos(state.todos, action)
}
}
###4. Reducerが作成した新しいstateをstoreが保存する
Reducerによって新しいStateが作成されるので、Storeは現在のStateに代わり保持します。
Reactとの連携
相関図のViewの部分がReactJSが担う部分となります。
実装については「Redux入門 6日目 ReduxとReactの連携」を参照してください。
##Reduxの3原則
最後になりますが、Reduxの基本設計は以下の3つの原則に基づいて設計されています。
上記のデータフローはこの原則に則っていることがよく分かると思います。
###1. Single source of truth
アプリケーション内でStoreは1つのみとし、Stateは単独のオブジェクトとしてStoreに保持される。
2. State is read-only
Stateを直接変更することはできず、actionをStoreへdispatchすることでしかStateは変更できない。
3. Mutations are written as pure functions
Stateを変更する関数(Reducer)はpureな関数にする。
##最後に
以上がReduxの基礎となります。詳しく掘り下げたい場合は以下の記事を参考にしてください。
- Redux入門 1日目 Reduxとは
- Redux入門 2日目 Reduxの基本・Actions
- Redux入門 3日目 Reduxの基本・Reducers
- Redux入門 4日目 Reduxの基本・Stores
- Redux入門 5日目 Reduxの基本・Data Flow
- Redux入門 6日目 ReduxとReactの連携
2018/4/25 追記
React本体が提供するReduxライクな機能であるContextAPIについて書きました。
- [ReactのContext APIはReduxの代わりとなるのか]
(https://qiita.com/kiita312/items/8da6b429949a36ee2420)