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。