在學習Redux以前,不妨先了解下Flux:javascript
一個基本的流程能夠描述爲html
與React關係能夠理解爲:前端
Flux:是一個系統架構,用於推動應用中的數據單向流動 React:是一個JavaScript庫,用於構建「可預期」和「聲明式」的可組合式Web用戶界面
問題vue
參考java
Flux架構入門教程 - ryfeng;python
Flux For Stupid People;react
一篇漫畫,圖解Flux;git
Redux是基於Flux架構思想的一個庫的實現,JavaScript狀態容器,提供可預測化的狀態管理。es6
設計思想github
三大原則
顯著特色
核心元素
Redux中的 reducer 就是一個純函數,store.dispatch(_action) 會自動觸發 reducer 方法,更新state。
注意,reducer方法不會改變state,而是返回一個全新的state對象。
關於純函數:一樣的輸入,一定獲得一樣的輸出
Date.now()
或Math.random()
等不純的方法,由於每次會獲得不同的結果適用場景
多交互、多數據源
關於Redux的生態系統,請參見:http://www.redux.org.cn/docs/introduction/Ecosystem.html
store
本質:狀態樹
let { subscribe, dispatch, getState } = createStore(reducer);
關於createStore的基本實現,輔助理解
function createStore(reducer, initialState) { //閉包私有變量 var currentReducer = reducer; var currentState = initialState; var listeners = []; function getState() { return currentState; } function subscribe(listener) { listeners.push(listener); return function unsubscribe() { var index = listeners.indexOf(listener); listeners.splice(index, 1); }; } function dispatch(action) { currentState = currentReducer(currentState, action); listeners.slice().forEach(listener => listener()); return action; } //返回一個包含可訪問閉包變量的公有方法 return {dispatch, subscribe, getState}; }
store能夠看做是對reducer的封裝,經過store.dispatch(action)自動觸發對reducer的調用,而不是直接調用reducer(currentState, action),在必定程度上能夠避免頻繁傳參,以更好地對store進行統一管理。
Action & Action Creator & bindActionCreators
var actionCreatorsNew = bindActionCreators(actionCreators, store.dispatch);
借鑑store對reducer的封裝,對store.dispatch做封裝,自動把actionCreators綁定到dispatch,使actionCreators成爲具備操做全局state的函數集合。
其中,actionCreators表示action集合。觸發action,會自動調用dispatch(action),避免直接對dispatch的調用。
middleware
異步場景:在異步操做結束後自動執行reducer
即,如何在操做結束時,自動送出第二個 Action
擴展點:dispatch()發出時,reducer()處理前
對於中間件,舉例,日誌中間件 redux-logger
import { applyMiddleware, createStore } from 'redux'; import createLogger from 'redux-logger'; const logger = createLogger(); const store = createStore(reducer, initial_state, applyMiddleware(logger) );
other,請注意中間件的引入次序。
給出 applymiddleware 的實現,僅供參考
export default function applyMiddleware(...middlewares) { return (createStore) => (reducer, preloadedState, enhancer) => { var store = createStore(reducer, preloadedState, enhancer); var dispatch = store.dispatch; var chain = []; var middlewareAPI = { getState: store.getState, dispatch: (action) => dispatch(action) }; chain = middlewares.map(middleware => middleware(middlewareAPI)); dispatch = compose(...chain)(store.dispatch); return {...store, dispatch} } }
其中,compose 用於組合函數、串聯鏈式執行,順序自右向左,維護擴展方便
var greeting = (firstName, lastName) => 'hello, ' + firstName + ' ' + lastName var toUpper = str => str.toUpperCase() var fn = compose(toUpper, greeting) console.log(fn('jack', 'smith')) // ‘HELLO,JACK SMITH’
異步狀況,涉及發出三種不一樣種類的 Action
同時,state須要維護、以反映不一樣的操做狀態
let state = { // ... isFetching: true, // 表示是否在抓取數據 didInvalidate: true, // 表示數據是否過期 lastUpdated: 'xxxxxxx' // 表示上一次更新時間 };
整個異步操做流程應該是這樣的
在Redux中,中間件是純粹的函數,有明確的使用方法而且嚴格的遵循如下格式:
var anyMiddleware = function ({ dispatch, getState }) { return function(next) { return function (action) { // 你的中間件業務相關代碼 } } }
全部的這些,applyMiddleware會所有替咱們封裝實現。
異步解決方案能夠引入中間件 redux-thunk 或 redux-promise
可是,二者均是相對原始的解決方案,在action須要組合、取消時操做不易處理。最佳實踐dva推薦 redux-saga,可測試、可mock、聲明式的指令,管理actions,處理異步邏輯,管理全部的業務邏輯。
組件分類
Redux的重要思想就是:容器組件和展現組件的分離
業務邏輯:針對UI組件
在網上看到一個很是不錯的關係圖,分享給你們
connect
將 UI 組件生成容器組件:
const HocView = connect(mapStateToProps, mapDispatchToProps)(myComp)
其中,mapStateToProps
負責輸入邏輯、將狀態數據state映射到 UI 組件的參數props,mapDispatchToProps
負責輸出邏輯、將用戶對 UI 組件的操做映射成 Action。
mapStateToProps會訂閱Store,每當state更新,就會自動執行,從新計算 UI 組件的參數,從而觸發 UI 組件的從新渲染。
<Provider>
用來實現對store的全局訪問,使容器組件獲取到state:
render( <Provider store={store}> <Root /> </Provider>, document.getElementById('root') )
原理是利用React的 context 屬性:
class Provider extends Component { getChildContext() { return { store: this.props.store }; } render() { return this.props.children; } } Provider.childContextTypes = { store: React.PropTypes.object }
子組件經過 this.context.store 獲取。一個簡單的計數器例子,供參見。
Redux擴展: redux-devtools-extension
使用步驟
redux-devtools-extension
包參考
Redux教程(1-4) - 阮一峯;Redux視頻前30集;後30集;
redux在react中的應用(基礎篇);redux入門教程;
看漫畫,學Redux;redux 三重境 - 對 redux 最佳實踐的思考和總結;
前面提到 redux-saga 能夠做爲 Redux 的異步解決方案,簡單學習之,爲後面學習 dva 做個鋪墊。
A Redux middleware for handling side effects (異步任務).
Redux中間件,基於ES6的Generator功能,用於管理應用程序Side Effect的庫,反作用例如
建議先了解下 Generator語法。經過redux-saga中間件將 Saga 與 Redux Store 創建鏈接:
import { createStore, applyMiddleware } from 'redux' import createSagaMiddleware from 'redux-saga' import reducer from './reducers' import mySaga from './sagas' const sagaMiddleware = createSagaMiddleware(); const store = createStore(reducer, applyMiddleware(sagaMiddleware)); sagaMiddleware.run(mySaga); /// then run the saga
其中,'./sagas' 用於處理全部異步操做邏輯,'./reducers' 用於處理action對stage更新。
參考
redux-saga | 中文教程; redux-saga-beginner-tutorial;
由支付寶前端團隊開發,相關歷史可參見:支付寶前端應用架構的發展和選擇: 從 roof 到 redux 再到 dva
相關簡介參見:dva - what&why -簡介;
注意,dva 是 framework,而 redux 是 library。
最核心功能是提供 app.model 方法,用於把 reducer, initialState, action, saga 封裝到一塊兒
每一個路由對應一個model,這個model掌管該路由的全部狀態(action、state、reducer、sagas),組件想改變狀態只要dispatch type便可。
參考