Action/Reducer/Store
首先,先看看第一張圖,圖中展示了Redux的單向數據流,以及Action、Reducer和Store這三個核心概念。
下面就圍繞上圖,非別介紹Action、Reducer和Store這三個概念。
Action和Action Creator
Action是一個對象,用來代表所有會引起狀態(state)變化的行為(例如服務端的響應,頁面上的用戶操作)。
假如我們要實現一個任務管理系統,那么添加任務的Action對象就會是下面的形式:
{ type: 'ADD_TASK', name: 'Read ES6 spec', category: 'Reading' }
Action對象是行為的描述,一般都會包含下面的信息:
- 一個字符串類型的type字段來表示將要執行的動作
- 需要傳遞給應用的其他數據信息(例子中的name和category),數據形式用戶可以自定義
Action通過Action創建函數(Action Creator)來創建,Action Creator是一個函數,最終返回一個Action對象。
對於添加任務這個行為,對應的Action Creator如下:
function addTask(name, category) { return { type: ADD_TASK, name, category }; }
Reducer
Action對象僅僅是描述了行為的相關信息,至於如何通過特定的行為來更新state,就需要看看Reducer了。
關於Reducer,最簡單的描述就是:
- Reducer是一個函數
- 該函數接收兩個參數,一個舊的狀態previousState和一個Action對象
- 返回一個新的狀態newState
根據上面的描述,Reducer函數就可以表示為:
(previousState, action) => newState
Reducer函數的形式通常如下:
function reducer(state = [], action) { // 處理不同action的代碼 switch (action.type) { case SPECIAL_ACTION: // 根據SPECIAL_ACTION action更新state // 返回新的state default: return state } }
Store
Actions描述了"what happened"的事實,Reducers則根據這些actions來更新state,而Store則是Actions和Reducers連接在一起的對象。
Store是Redux中數據的統一存儲,維護着state的所有內容,所以Store的主要功能就是:
- 維護應用的state內容
- 提供getState()方法獲取 state
- 提供dispatch(action)方法更新 state
- 提供subscribe(listener)方法注冊監聽器
看到Store提供的方法,就可以把Action、Reducer和Store聯系在一起了:
- Store通過dispatch(action)方法來接收不同的Action
- 根據Action對象的type和數據信息,Store對象可以通過Reducer函數來更新state的內容
Middleware
下面就來看看第二張圖,跟第一張圖的差別不大,只是增加了中間件(Middleware)來處理Action。
在Redux中,Middlerwares主要的作用就是處理Action,Redux中的Action必須是一個plain object。但是為了實現異步的Action或其他功能,這個Action可能就是一個函數,或者是一個promise對象。這是就需要中間件幫助來處理這種特殊的Action了。
也就是說,Redux中的Middleware會對特定類型action做一定的轉換,所以最后傳給reducer的action一定是標准的plain object。
針對Action的特征,Reudx Middleware可以采取不同的操作:
- 可以選擇傳遞給下一個中間件,如:next(action)
- 可以選擇跳過某些中間件,如:dispatch(action)
- 或者更直接了當的結束傳遞,如:return。
Redux中常用的中間件:
- redux-thunk:action可以是一個函數,用來發起異步請求。
- redux-promise:action可以是一個promise對象,用來更優雅的進行異步操作。
- redux-logger:action就是一個標准的plain object,用來記錄action和nextState的。
react-redux
經過前面的介紹,我們已經看到了Redux中的一些核心概念。Redux跟React沒有直接的關系,本身可以支持React、Angular、Ember等等框架。
通過react-redux這個庫,可以方便的將react和redux結合起來:react負責頁面展現,redux負責維護/更新數據狀態。
到這里,第三張圖就展示了react-redux這個庫的工作原理,react和redux是怎么聯系到一起的。
react-redux中提供了兩個重要功能模塊Provider和connect,這兩個模塊保證了react和redux之間的通信,下面就分別看看這兩個模塊。
Provider
通過Provider的代碼可以看到,Provide本質上是一個react組件。
export default class Provider extends Component { getChildContext() { return { store: this.store } } constructor(props, context) { super(props, context) this.store = props.store } render() { const { children } = this.props return Children.only(children) } }
Provider組件主要用到了react通過context屬性,可以將屬性(props)直接給子孫component,無須通過props層層傳遞,從而減少組件的依賴關系。
connect
connect方法的主要作用就是讓Component與Store進行關聯, Store的數據變化可以及時通知Views重新渲染。
任何一個通過connect()函數處理過的組件都可以得到一個dispatch方法作為組件的props,以及得到全局state中的所有內容。
通過源碼]可以看到,connect函數運行后,會返回一個wrapWithConnect函數,該函數可以接收一個react組件,然后返回一個經過處理的Connect組件。
return function wrapWithConnect(WrappedComponent) { class Connect extends Component { constructor(props, context) { // 從祖先Component處獲得store this.store = props.store || context.store this.stateProps = computeStateProps(this.store, props) this.dispatchProps = computeDispatchProps(this.store, props) this.state = { storeState: null } // 對stateProps、dispatchProps、parentProps進行合並 this.updateState() } shouldComponentUpdate(nextProps, nextState) { // 進行判斷,當數據發生改變時,Component重新渲染 if (propsChanged || mapStateProducedChange || dispatchPropsChanged) { this.updateState(nextProps) return true } } componentDidMount() { // 改變Component的state this.store.subscribe(() = { this.setState({ storeState: this.store.getState() }) }) } render() { // 生成包裹組件Connect return ( <WrappedComponent {...this.nextState} /> ) } } Connect.contextTypes = { store: storeShape } return Connect; }
詳細內容和demo
文中很多Redux的概念都是進行了簡單的介紹,更多詳細的介紹可以參考,GitHub地址:WilberTian/StepByStep-Redux
- 01.Action.md
- 02.Reducer.md
- 03.Store.md
- 04.Redux-data-flow.md
- 05.Middleware (part 1).md
- 05.Middleware (part 2).md
- 06.react-redux.md
每篇文章的結尾都會有一些簡單的demo 代碼,幫助理解文章中介紹的內容。
總結
文中結合三張圖片介紹了Redux中的一些核心概念,以及React和Redux之間通過react-redux這個庫進行交互。
更多詳細的內容,已經整理到了GitHub上了(WilberTian/StepByStep-Redux),通過這些介紹以及demo的運行結果,一定能對Redux有一個比較基本的認識。