Action 很简单,就是一个单纯的包含 { type, payload }
的对象,type
是一个常量用来标示动做类型,payload
是这个动做携带的数据。Action 须要经过 store.dispatch()
方法来发送。javascript
好比一个最简单的 action:java
{
type: 'ADD_TODO', text: 'Build my first Redux app' }
通常来讲,会使用函数(Action Creators)来生成 action,这样会有更大的灵活性,Action Creators 是一个pure function,它最后会返回一个 action 对象:git
function addTodo(text) { return { type: 'ADD_TODO', text } }
因此如今要触发一个动做只要调用 dispatch
: dispatch(addTodo(text))
github
稍后会讲到如何拿到 store.dispatch
redux
Reducer 用来处理 Action 触发的对状态树的更改。app
因此一个 reducer 函数会接受 oldState
和 action
两个参数,返回一个新的 state:(oldState, action) => newState
。一个简单的 reducer 可能相似这样:dom
const initialState = { a: 'a', b: 'b' }; function someApp(state = initialState, action) { switch (action.type) { case 'CHANGE_A': return { ...state, a: 'Modified a' }; case 'CHANGE_B': return { ...state, b: action.payload }; default: return state } }
值得注意的有两点:ecmascript
oldState
而是返回一个 newState
oldState
Reducer 也是 pure function,这点很是重要,因此绝对不要在 reducer 里面作一些引入 side-effects 的事情,好比:ide
Data.now()
Math.random()
由于 Redux 里面只有一个 Store,对应一个 State 状态,因此整个 State 对象就是由一个 reducer 函数管理,可是若是全部的状态更改逻辑都放在这一个 reducer 里面,显然会变得愈来愈巨大,愈来愈难以维护。得益于纯函数的实现,咱们只须要稍微变通一下,让状态树上的每一个字段都有一个 reducer 函数来管理就能够拆分红很小的 reducer 了:函数
function someApp(state = {}, action) { return { a: reducerA(state.a, action), b: reducerB(state.b, action) }; }
对于 reducerA
和 reducerB
来讲,他们依然是形如:(oldState, action) => newState
的函数,只是这时候的 state 不是整个状态树,而是树上的特定字段,每一个 reducer 只须要判断 action,管理本身关心的状态字段数据就行了。
Redux 提供了一个工具函数 combineReducers
来简化这种 reducer 合并:
import { combineReducers } from 'redux'; const someApp = combineReducers({ a: reducerA, b: reducerB });
若是 reducer 函数名字和字段名字相同,利用 ES6 的 Destructuring 能够进一步简化成:combineReducers({ a, b })
象 someApp
这种管理整个 State 的 reducer,能够称为 root reducer。
如今有了 Action 和 Reducer,Store 的做用就是链接这二者,Store 的做用有这么几个:
getState()
方法获取 Statedispatch()
方法发送 action 更改 Statesubscribe()
方法注册回调函数监听 State 的更改建立一个 Store 很容易,将 root reducer 函数传递给 createStore
方法便可:
import { createStore } from 'redux'; import someApp from './reducers'; let store = createStore(someApp); // 你也能够额外指定一个初始 State(initialState),这对于服务端渲染颇有用 // let store = createStore(someApp, window.STATE_FROM_SERVER);
如今咱们就拿到了 store.dispatch
,能够用来分发 action 了:
let unsubscribe = store.subscribe(() => console.log(store.getState())); // Dispatch store.dispatch({ type: 'CHANGE_A' }); store.dispatch({ type: 'CHANGE_B', payload: 'Modified b' }); // Stop listening to state updates unsubscribe();
以上提到的 store.dispatch(action) -> reducer(state, action) -> store.getState()
其实就构成了一个“单向数据流”,咱们再来总结一下。
1. 调用 store.dispatch(action)
Action 是一个包含 { type, payload }
的对象,它描述了“发生了什么”,好比:
{ type: 'LIKE_ARTICLE', articleID: 42 } { type: 'FETCH_USER_SUCCESS', response: { id: 3, name: 'Mary' } } { type: 'ADD_TODO', text: 'Read the Redux docs.' }
你能够在任何地方调用 store.dispatch(action)
,好比组件内部,Ajax 回调函数里面等等。
2. Action 会触发给 Store 指定的 root reducer
root reducer 会返回一个完整的状态树,State 对象上的各个字段值能够由各自的 reducer 函数处理并返回新的值。
(state, action)
两个参数action.type
而后处理对应的 action.payload
数据来更新并返回一个新的 state3. Store 会保存 root reducer 返回的状态树
新的 State 会替代旧的 State,而后全部 store.subscribe(listener)
注册的回调函数会被调用,在回调函数里面能够经过 store.getState()
拿到新的 State。
这就是 Redux 的运做流程,接下来看如何在 React 里面使用 Redux。