戻ってきた
Reduxは、予測可能な状態管理を提供するJavaScript状態コンテナーです。
インストール
npm install --save redux
ポイント
アプリケーションのすべての状態は、オブジェクトツリーの形式で単一のストアに格納されます。状態を変更する唯一の方法は、何が起こるかを説明するオブジェクトであるactionをトリガーすることです。アクションがどのように状態ツリーを変更するかを説明するには、reducerを作成する必要があります。
例
import {
createStore } from 'redux';
/*
这是一个reducer,形式为 (state, action) => state 的纯函数
描述了 action 如何把 state 转变为下一个state
state 的形式,可以是基本类型/数组/对象 等等
唯一的要点是 当 state 变化时需要返回全新的对象,而不是修改传入的参数
*/
function counter (state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
default:
return state;
}
}
// 创建 Redux store 存放应用的状态
// API 是 { subscribe, dispatch, getState }
let store = createStore(counter)
// 可以手动订阅更新,也可以事件绑定到视图层
store.subscribe(() =>
console.log(store.getState())
)
// 改变内部 state 唯一的方法是 dispatch 一个 action
// action 可以被序列化,用日记记录和存储下来,后期可以以回放的方式执行
store.dispatch({
type: 'INCREMENT' }) // 1
store.dispatch({
type: 'INCREMENT' }) // 2
store.dispatch({
type: 'DECREMENT' }) // 1
キーコンセプト
通常のオブジェクトを使用してアプリケーションの状態を説明する場合。たとえば、Todoアプリケーションの状態は次のようになります。
{
todos: [{
text: 'Eat food',
completed: true
},
{
text: 'Exercise',
completed: false
}],
visibilityFilter: 'SHOW_COMPLETED'
}
このオブジェクトは「モデル」のようなものです。違いは、セッター(修飾子メソッド)がないことです。したがって、他のコードは自由に変更できず、再現が困難なバグが発生します。
状態のデータを更新するには、アクションを開始する必要があります。アクションは、何が起こったかを説明するための単なる通常のJavaScriptオブジェクトです(ここには魔法がないことに注意してください)。次にアクションの例をいくつか示します。
{
type: 'ADD_TODO', text: 'Go to swimming pool' }
{
type: 'TOGGLE_TODO', index: 1 }
{
type: 'SET_VISIBILITY_FILTER', filter: 'SHOW_ALL' }
アクションを使用してすべての変更の利点を説明することは、アプリケーションで何が起こっているかを明確に知ることです。何かが変わった場合、その理由を知ることができます。アクションは、何が起こったかを示すインジケーターのようなものです。最後に、アクションと状態をリンクし、いくつかの機能を開発するために、これはレデューサーです。繰り返しになりますが、何の魔法もなく、レデューサーは状態とアクションを受け取り、新しい状態を返す関数にすぎません。
大規模なアプリケーションの場合、そのような関数を1つだけ作成することは不可能であるため、状態の一部を個別に管理するための多数の小さな関数を作成します。
function visibilityFilter(state = 'SHOW_ALL', action) {
if(action.type === 'SET_VISIBILITY_FILTER') {
return action.filter;
} else {
return state;
}
}
function todos(state = [], action) {
switch(action.type) {
case 'ADD_TODO':
return state.concat([{
text: action.text, completed: false }])
case 'TOGGLE_TODO':
return state.map((todo, index) =>
action.index === index ?
{
text: todo.text, completed: !todo.completed } : todo
)
default:
return state;
}
}
次に、これら2つのレデューサーを呼び出してアプリケーション全体の状態を管理するレデューサーを開発します。
function todoApp(state = {
}, action) {
return {
todos: todos(state.todos, action),
visibilityFilter: visibilityFilter(state.visibilityFilter, action)
}
}
3つの原則
単一のデータソース
アプリケーション全体state
はオブジェクトツリーに格納され、このオブジェクトツリーは1つだけに存在しstore
ます。
console.log(store.getState());
/* 输出
{
visibilityFilter: 'SHOW_ALL',
todos: [
{
text: 'Consider using Redux',
completed: true
},
{
text: 'Keep all state in a single tree',
completed: false
}
]
}
*/
状態は読み取り専用です
状態を変更する唯一の方法は、をトリガーすることaction
です。アクションは、発生したイベントを説明するために使用される通常のオブジェクトです。
これにより、ビューもネットワークリクエストも状態を直接変更できないことが保証されます。逆に、変更の意図を表現することしかできません。すべての変更が一元的に処理され、厳密な順序で次々に実行されるためです。アクションは単なる通常のオブジェクトであるため、テスト中に印刷、シリアル化、保存、デバッグ後、または再生できます。
store.dispatch({
type: 'COMPLETE_TODO',
index: 1
})
store.dispatch({
type: 'SET_VISIBILITY_FILTER',
filter: 'SHOW_COMPLETED'
})
純粋な関数を使用して変更を実行する
アクションがどのように状態ツリーを変更するかを説明するには、次のように記述する必要がありますreducers
レデューサーは単なる純粋な関数であり、以前の状態とアクションを受け取り、新しい状態を返します。最初は、レデューサーを1つだけ持つことができます。アプリケーションが大きくなると、それを複数の小さなレデューサーに分割し、状態ツリーのさまざまな部分を個別に操作できます。レデューサーは単なる関数なので、呼び出される順序を制御できます。追加のデータを渡します。
function visibilityFilter(state = 'SHOW_ALL', action) {
switch (action.type) {
case 'SET_VISIBILITY_FILTER':
return action.filter
default:
return state
}
}
function todos(state = [], action) {
switch(action.type) {
case 'ADD_TODO':
return [
...state,
{
text: action.text,
completed: false
}
]
case 'COMPLETE_TODO':
return state.map((todo, index) => {
if(index === action.index) {
return Object.assign({
}, todo, {
completed: true
})
}
return todo
})
default:
return state
}
}
import {
combineReducers, createStore } from 'redux'
let reducer = combineReducers({
visibilityFilter, todos })
let store = createStore(reducer)