一,背景es6
Redux在mobx以前出現,redux基於Elm, flux, Immutable.js 的思想對狀態管理從新作了優化。redux
在項目中使用時,Redux對數據更新和管理,能夠很容易擴展插件,中間件等。api
二,redux提供的api數組
1,composeapp
對傳入的函數進行從右往左的方式編譯,函數的合併。異步
代碼實現以下:async
/** * 從右往左,編譯單個參數的函數。最右函數能夠是多個參數的函數,提供單個編譯函數。 * * @param {...Function} funcs The functions to compose. * @returns {Function} A function obtained by composing the argument functions * from right to left.
* For example, compose(f, g, h) is identical to doing * (...args) => f(g(h(...args))). */ function compose() { for (var _len = arguments.length, funcs = new Array(_len), _key = 0; _key < _len; _key++) { funcs[_key] = arguments[_key]; } if (funcs.length === 0) { return function (arg) { return arg; }; } if (funcs.length === 1) { return funcs[0]; } // reduce 屢次迴歸調用,函數是一個包裹的過程,從左往右包裹,執行時從右往左執行。
// 最後返回一個能夠執行全部函數的 函數! return funcs.reduce(function (a, b) { return function () { return a(b.apply(void 0, arguments)); }; }); }
2,bindActionCreator / bindActionCreatorside
將action和dispatch合併,做爲action的creator。函數
// 源碼這裏 調用函數會返回一個函數,函數執行會返回dispatch執行action的結果,至關於提早執行了dispatch。
function bindActionCreator(actionCreator, dispatch) { return function () { return dispatch(actionCreator.apply(this, arguments)); }; }
bindActionCreator 是爲了提早獲取dispatch action的結果,還提供了bindActionCreators優化
/** *
* 轉換每個action creator,將其返回的對象的key都進行 dispatch 包裹,方便直接調用。
* 爲了方便,也能夠在creator 的第一個參數傳入dispatch,用dispatch包裹後再返回。 * * @param {Function|Object} actionCreators An object whose values are action * creator functions. One handy way to obtain it is to use ES6 `import * as` * syntax. You may also pass a single function.
* 和es6 的 import * as 語法結合使用,傳入對象或者函數。 * * @param {Function} dispatch The `dispatch` function available on your Redux * store. * */ function bindActionCreators(actionCreators, dispatch) {
// 判斷是不是函數 if (typeof actionCreators === 'function') { return bindActionCreator(actionCreators, dispatch); }
// 判斷是不是不是null的對象 if (typeof actionCreators !== 'object' || actionCreators === null) { throw new Error("bindActionCreators expected an object or a function, instead received " + (actionCreators === null ? 'null' : typeof actionCreators) + ". " + "Did you write \"import ActionCreators from\" instead of \"import * as ActionCreators from\"?"); } // 定義新對象,存儲傳參對象調用 bindActionCreator 的返回值。 var boundActionCreators = {}; // 若是是對象執行 for-in 循環(for-in專用於遍歷對象的key。) for (var key in actionCreators) { var actionCreator = actionCreators[key]; // 對每一個對象中的function都調用一次上面的 bindActionCreator() 函數。 if (typeof actionCreator === 'function') { boundActionCreators[key] = bindActionCreator(actionCreator, dispatch); } } // 返回新的對象 return boundActionCreators; }
3,applyMiddleware
const composeEnhancers = composeWithDevTools({ actionCreators, trace: true, traceLimit: 25 }); const store = createStore(reducer, preloadedState, composeEnhancers( // 引入中間件的方式
applyMiddleware(invariant(), thunk)
));
return store; ));
查看這個中間件須要先看一個關鍵的函數:_objectSpread2
_objectSpread2 函數代碼以下
// es6 的方式把對象的key
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) {
// push.apply 數組的合併,獲取可枚舉的key + 符號類型的key(是否可枚舉都獲取到),獲得完整的key數組。 keys.push.apply(keys, Object.getOwnPropertySymbols(object)); } // 過濾掉不能枚舉的屬性 if (enumerableOnly) keys = keys.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); return keys; // 返回對象的key數組 }
// redux加載中間件 關鍵的函數
// function _objectSpread2(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {};
// 若是資源的下標是偶數 if (i % 2) { ownKeys(source, true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(source).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
/** * * 引用中間件以豐富修改 redux store 的dispatch方法。
* 知足不一樣的任務,用簡明的方式實現,例如:異步action,日誌等。
* * 參考 `redux-thunk` 就是處理異步的中間件。 * * Because middleware is potentially asynchronous, this should be the first * store enhancer in the composition chain.
* 由於中間件是潛在的異步過程,應該是在組和鏈中第一個被調用 * * Note that each middleware will be given the `dispatch` and `getState` functions * as named arguments.
* 每一箇中間件都應該有 dispatch 和 getState 方法。 * * @param {...Function} middlewares The middleware chain to be applied. * @returns {Function} A store enhancer applying the middleware.
* 而後返回應用中間件的store enhancer 狀態值的放大器。
* 重點意思是,對action的再次封裝返回新的action。 */ function applyMiddleware() {
// 遍歷函數arguments,並將參數從新收集到一個新的 middlewares 數組。 for (var _len = arguments.length, middlewares = new Array(_len), _key = 0; _key < _len; _key++) { middlewares[_key] = arguments[_key]; } return function (createStore) { return function () { var store = createStore.apply(void 0, arguments);
// 引用中間件不被容許的提示。 var _dispatch = function dispatch() { throw new Error('Dispatching while constructing your middleware is not allowed. ' + 'Other middleware would not be applied to this dispatch.'); };
// store的 getState dispatch 方法,拿過來給每一箇中間件都是 var middlewareAPI = { getState: store.getState, dispatch: function dispatch() { return _dispatch.apply(void 0, arguments); } }; var chain = middlewares.map(function (middleware) {
// 將getState和dispatch傳遞給中間件 return middleware(middlewareAPI); });
//把添加getState和dispatch的中間件數組,調用 compose 進行一次dispatch的合併,返回一個函數再次調用獲得新的dispatch。 _dispatch = compose.apply(void 0, chain)(store.dispatch); return _objectSpread2({}, store, { dispatch: _dispatch }); }; }; }
4,composeEnhancers