标签:
有理解不对的地方,欢迎大家指正!!!
react为什么需要redux辅助???react是view层的单向数据流框架,数据需要一层一层往子组件传递(子组件并不会自动继承)。子组件需要操作父组件的数据时,需要父组件给子组件传递一个方法,子组件调用该方法才能改变父组件的数据。如果组件的层次太深会这种传递会很繁琐,令代码沉余。用redux能很好解决这个问题,redux+react-redux可以使一个容器内的数据通过this.props共享,避免了一层层传递数据繁琐的操作。
redux使用了纯函数写法,这种编程模式就是函数式编程(简称:fb)。rudex使用了大量的设计模式比较,如:装饰者模式(包装),工厂模式,桥接模式,代理模式,观察者模式。
装饰者模式:包装了action、dispatch、createStore,扩展本身满足需求;
工厂模式:action包装器也是一个工厂,通过该方法生产新的action;
代理模式:applyMiddleware返回一个方法回去取需要的createStore方法;
桥接模式:isPlainObject通过连接isHostObject与isObjectLike方法来完成新的功能;
观察者模式:通过subscribe添加事件队列,dispatch执行事件队列与更新state;
模块1:其实模块1并没有什么好介绍的,主体就一个compose方法为模块5的applyMiddleware方法服务,把applyMiddleware的参数串联执行,最后返回包装的dispatch。
/* 1 */ /***/ function(module, exports) { "use strict"; exports.__esModule = true; exports["default"] = compose; /** * Composes single-argument functions from right to left. * * @param {...Function} funcs The functions to compose. * @returns {Function} A function obtained by composing functions from right to * left. For example, compose(f, g, h) is identical to arg => f(g(h(arg))). */ //compose为模块5的applyMiddleware方法服务,把applyMiddleware的参数串联执行返回包装的dispatch function compose() { //复制参数 for (var _len = arguments.length, funcs = Array(_len), _key = 0; _key < _len; _key++) { funcs[_key] = arguments[_key]; }return function () { if (funcs.length === 0) { return arguments.length <= 0 ? undefined : arguments[0]; } var last = funcs[funcs.length - 1]; //最后一个参数 var rest = funcs.slice(0, -1); //除了最后一个参数外的所有参数
//从右到左串联执行rest参数列表里的方法 return rest.reduceRight(function (composed, f) { return f(composed); }, last.apply(undefined, arguments)); } /***/ },
模块2:主体createStore方法,createStore方法里主要包含:subscribe--订阅事件,dispatch---发布事件
其实他们做的事都很简单:subscribe把接受的push(入栈)进一个数组,dispatch被调用时则依次执行数组里的方法
1 /* 2 */ 2 /***/ function(module, exports, __webpack_require__) { 3 4 ‘use strict‘; 5 6 exports.__esModule = true; 7 exports.ActionTypes = undefined; 8 exports["default"] = createStore; 9 10 var _isPlainObject = __webpack_require__(4); 11 12 var _isPlainObject2 = _interopRequireDefault(_isPlainObject); 13 //初始化 14 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } 15 16 /** 17 * These are private action types reserved by Redux. 18 * For any unknown actions, you must return the current state. 19 * If the current state is undefined, you must return the initial state. 20 * Do not reference these action types directly in your code. 21 */ 22 var ActionTypes = exports.ActionTypes = { 23 INIT: ‘@@redux/INIT‘ 24 }; 25 //创建store树 51 function createStore(reducer, initialState, enhancer) {
//参数匹配 52 if (typeof initialState === ‘function‘ && typeof enhancer === ‘undefined‘) { 53 enhancer = initialState; 54 initialState = undefined; 55 } 56 57 if (typeof enhancer !== ‘undefined‘) { 58 if (typeof enhancer !== ‘function‘) { 59 throw new Error(‘Expected the enhancer to be a function.‘); 60 } 61 //enhancer扩展createStore进行扩展 62 return enhancer(createStore)(reducer, initialState); 63 } 64 65 if (typeof reducer !== ‘function‘) { 66 throw new Error(‘Expected the reducer to be a function.‘); 67 } 68 69 var currentReducer = reducer; 70 var currentState = initialState; 71 var currentListeners = []; //存储事件队列 72 var nextListeners = currentListeners; //存储备份事件队列 73 var isDispatching = false; 74 //备份事件队列---此方法存在的意义:防止在队列中操作事件队列(对事件队列增删)导致数据混乱 75 function ensureCanMutateNextListeners() { 76 if (nextListeners === currentListeners) { 77 nextListeners = currentListeners.slice(); 78 } 79 } 80
//获取state 86 function getState() { 87 return currentState; 88 } 89 113 //订阅事件 114 function subscribe(listener) { 115 if (typeof listener !== ‘function‘) { 116 throw new Error(‘Expected listener to be a function.‘); 117 } 118 //保证事件只能被卸载一次 119 var isSubscribed = true; 120 121 ensureCanMutateNextListeners(); 122 nextListeners.push(listener); 123 //闭包缓存正在监听的事件,可以通过:var unsub=subscribe(listener); unsub()来卸载此事件 124 return function unsubscribe() { 125 if (!isSubscribed) { 126 return; 127 } 128 isSubscribed = false; 129 //备份事件队列再进行卸载操作 130 ensureCanMutateNextListeners(); 131 var index = nextListeners.indexOf(listener); 132 nextListeners.splice(index, 1); 133 }; 134 } 135 161 //发布事件 162 function dispatch(action) { 163 //检测action是否是字面量对象 164 if (!(0, _isPlainObject2["default"])(action)) { 165 throw new Error(‘Actions must be plain objects. ‘ + ‘Use custom middleware for async actions.‘); 166 } 167 168 if (typeof action.type === ‘undefined‘) { 169 throw new Error(‘Actions may not have an undefined "type" property. ‘ + ‘Have you misspelled a constant?‘); 170 } 171 172 if (isDispatching) { 173 throw new Error(‘Reducers may not dispatch actions.‘); 174 } 175 176 try { 177 isDispatching = true; 178 //执行reducer更新state 179 currentState = currentReducer(currentState, action); 180 } finally { 181 isDispatching = false; 182 } 183 //同步事件队列---执行最新的事件队列 184 var listeners = currentListeners = nextListeners; 185 for (var i = 0; i < listeners.length; i++) { 186 listeners[i](); 187 } 188 189 return action; 190 } 191 202 //替换reducer 203 function replaceReducer(nextReducer) { 204 if (typeof nextReducer !== ‘function‘) { 205 throw new Error(‘Expected the nextReducer to be a function.‘); 206 } 207 208 currentReducer = nextReducer; 209 dispatch({ type: ActionTypes.INIT }); 210 } 211 212 //初始化state 215 dispatch({ type: ActionTypes.INIT }); 216 217 return { 218 dispatch: dispatch, 219 subscribe: subscribe, 220 getState: getState, 221 replaceReducer: replaceReducer 222 }; 223 } 224 225 /***/ },
模块4:模块3很简单就此跳过,咱们进入模块4。模块4也比较简单主体:isPlainObject方法主要是检测是否是字面量对象或者是直接实例化Object构造函数的实例对象
1 /* 4 */ 2 /***/ function(module, exports, __webpack_require__) { 3 4 var isHostObject = __webpack_require__(8), 5 isObjectLike = __webpack_require__(9); 6 7 /** `Object#toString` result references. */ 8 var objectTag = ‘[object Object]‘; 9 10 /** Used for built-in method references. */ 11 var objectProto = Object.prototype; 12 13 /** Used to resolve the decompiled source of functions. */ 14 var funcToString = Function.prototype.toString; 15 16 /** Used to infer the `Object` constructor. */ 17 var objectCtorString = funcToString.call(Object); 18 19 /** 20 * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring) 21 * of values. 22 */ 23 var objectToString = objectProto.toString; 24 25 /** Built-in value references. */ 26 var getPrototypeOf = Object.getPrototypeOf; 27 28 /** 29 * Checks if `value` is a plain object, that is, an object created by the 30 * `Object` constructor or one with a `[[Prototype]]` of `null`. 31 * 32 * @static 33 * @memberOf _ 34 * @category Lang 35 * @param {*} value The value to check. 36 * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. 37 * @example 38 * 39 * function Foo() { 40 * this.a = 1; 41 * } 42 * 43 * _.isPlainObject(new Foo); 44 * // => false 45 * 46 * _.isPlainObject([1, 2, 3]); 47 * // => false 48 * 49 * _.isPlainObject({ ‘x‘: 0, ‘y‘: 0 }); 50 * // => true 51 * 52 * _.isPlainObject(Object.create(null)); 53 * // => true 54 */ 55 //判断是否由Object直接构造出来的实例 56 function isPlainObject(value) { 57 if (!isObjectLike(value) || objectToString.call(value) != objectTag || isHostObject(value)) { 58 return false; 59 } 60 var proto = objectProto; 61 if (typeof value.constructor == ‘function‘) { 62 proto = getPrototypeOf(value); 63 } 64 //参数的构造函数时function且原型是null 65 if (proto === null) { 66 return true; 67 } 68 var Ctor = proto.constructor; 69 return (typeof Ctor == ‘function‘ && 70 Ctor instanceof Ctor && funcToString.call(Ctor) == objectCtorString); 71 } 72 73 module.exports = isPlainObject; 74 75 76 /***/ },
模块5:此模块的逻辑比较复杂,但是实现的东西却很简单:包装了createStore方法与createStore里的dispatch方法,使dispath支持异步。
applyMiddleware参数是redux提供的两个中间件:redux-thunks、redux-logger,两个模块提供方法对dispatch进行了包装。
1 /* 5 */ 2 /***/ function(module, exports, __webpack_require__) { 3 4 ‘use strict‘; 5 6 var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; 7 8 exports.__esModule = true; 9 exports["default"] = applyMiddleware; 10 11 var _compose = __webpack_require__(1); 12 13 var _compose2 = _interopRequireDefault(_compose); 14 15 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } 16 //包装createStore与dispatch 17 function applyMiddleware() { 18 for (var _len = arguments.length, middlewares = Array(_len), _key = 0; _key < _len; _key++) { 19 middlewares[_key] = arguments[_key]; 20 } 21 return function (createStore) { 22 //返回一个包装的createStore 23 return function (reducer, initialState, enhancer) { 24 var store = createStore(reducer, initialState, enhancer); 25 var _dispatch = store.dispatch; 26 var chain = []; 27 28 var middlewareAPI = { 29 getState: store.getState, 30 dispatch: function dispatch(action) { 31 return _dispatch(action); 32 } 33 }; 34 chain = middlewares.map(function (middleware) { 35 return middleware(middlewareAPI); 36 }) 37 //下面的代码其实就是执行:thunkMiddleware(middlewareAPI)(createLogger()(middlewareAPI)(dispatch))返回被包装的dispatch 38 _dispatch = _compose2["default"].apply(undefined, chain)(store.dispatch); 39 //将包装好的dispatch写入store 40 return _extends({}, store, { 41 dispatch: _dispatch 42 }); 43 }; 44 }; 45 }
redux-thunks模块里的thunkMiddleware方法:
1 function thunkMiddleware(_ref) { 2 var dispatch = _ref.dispatch; 3 var getState = _ref.getState; 4 5 return function (next) { 6 //返回一个包装的dispacth 7 return function (action) { 8 if (typeof action === ‘function‘) { 9 return action(dispatch, getState); 10 } 11 return next(action); //由于闭包next一直存在于包装的dispatch里,next其实是一个普通的dispatch,虽然经过了createLogger方法(redux-logger里面内置的一个方法)的包装, 但是主要作用与createStore定义时的dispatch方法是一样的 12 }; 13 }; 14 }
模块6:把action与dispatch方法绑定在一起,即把每个action包装着一个dispatch方法,然后执行action时就会自动dispath
1 /* 6 */ 2 /***/ function(module, exports) { 3 4 ‘use strict‘; 5 6 exports.__esModule = true; 7 exports["default"] = bindActionCreators;
//包装器---返回一个自动执行dispatch的方法 8 function bindActionCreator(actionCreator, dispatch) { 9 return function () { 10 return dispatch(actionCreator.apply(undefined, arguments)); 11 }; 12 } 13 35 36 function bindActionCreators(actionCreators, dispatch) { 37 if (typeof actionCreators === ‘function‘) { 38 return bindActionCreator(actionCreators, dispatch); 39 } 40 //判断是否是对象,不是对象则报错 41 if (typeof actionCreators !== ‘object‘ || actionCreators === null) { 42 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"?‘); 43 } 44 //获取键名数组 45 var keys = Object.keys(actionCreators); 46 var boundActionCreators = {}; 47 for (var i = 0; i < keys.length; i++) { 48 var key = keys[i]; 49 var actionCreator = actionCreators[key]; 50 if (typeof actionCreator === ‘function‘) { 51 //收集包装器返回的新的action方法 52 boundActionCreators[key] = bindActionCreator(actionCreator, dispatch); 53 } 54 } 55 return boundActionCreators; 56 }
模块7:执行reducers返回state
1 /* 7 */ 2 /***/ function(module, exports, __webpack_require__) { 3 4 ‘use strict‘; 5 6 exports.__esModule = true; 7 exports["default"] = combineReducers; 8 9 var _createStore = __webpack_require__(2); 10 11 var _isPlainObject = __webpack_require__(4); 12 13 var _isPlainObject2 = _interopRequireDefault(_isPlainObject); 14 15 var _warning = __webpack_require__(3); 16 17 var _warning2 = _interopRequireDefault(_warning); 18 19 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } 20 21 function getUndefinedStateErrorMessage(key, action) { 22 var actionType = action && action.type; 23 var actionName = actionType && ‘"‘ + actionType.toString() + ‘"‘ || ‘an action‘; 24 25 return ‘Reducer "‘ + key + ‘" returned undefined handling ‘ + actionName + ‘. ‘ + ‘To ignore an action, you must explicitly return the previous state.‘; 26 } 27 28 function getUnexpectedStateShapeWarningMessage(inputState, reducers, action) { 29 var reducerKeys = Object.keys(reducers); 30 var argumentName = action && action.type === _createStore.ActionTypes.INIT ? ‘initialState argument passed to createStore‘ : ‘previous state received by the reducer‘; 31 32 if (reducerKeys.length === 0) { 33 return ‘Store does not have a valid reducer. Make sure the argument passed ‘ + ‘to combineReducers is an object whose values are reducers.‘; 34 } 35 36 if (!(0, _isPlainObject2["default"])(inputState)) { 37 return ‘The ‘ + argumentName + ‘ has unexpected type of "‘ + {}.toString.call(inputState).match(/\s([a-z|A-Z]+)/)[1] + ‘". Expected argument to be an object with the following ‘ + (‘keys: "‘ + reducerKeys.join(‘", "‘) + ‘"‘); 38 } 39 40 var unexpectedKeys = Object.keys(inputState).filter(function (key) { 41 return !reducers.hasOwnProperty(key); 42 }); 43 44 if (unexpectedKeys.length > 0) { 45 return ‘Unexpected ‘ + (unexpectedKeys.length > 1 ? ‘keys‘ : ‘key‘) + ‘ ‘ + (‘"‘ + unexpectedKeys.join(‘", "‘) + ‘" found in ‘ + argumentName + ‘. ‘) + ‘Expected to find one of the known reducer keys instead: ‘ + (‘"‘ + reducerKeys.join(‘", "‘) + ‘". Unexpected keys will be ignored.‘); 46 } 47 } 48 //初始化reducers并检测时候会出错 49 function assertReducerSanity(reducers) { 50 Object.keys(reducers).forEach(function (key) { 51 var reducer = reducers[key]; 52 var initialState = reducer(undefined, { type: _createStore.ActionTypes.INIT }); 53 54 if (typeof initialState === ‘undefined‘) { 55 throw new Error(‘Reducer "‘ + key + ‘" returned undefined during initialization. ‘ + ‘If the state passed to the reducer is undefined, you must ‘ + ‘explicitly return the initial state. The initial state may ‘ + ‘not be undefined.‘); 56 } 57 58 var type = ‘@@redux/PROBE_UNKNOWN_ACTION_‘ + Math.random().toString(36).substring(7).split(‘‘).join(‘.‘); 59 if (typeof reducer(undefined, { type: type }) === ‘undefined‘) { 60 throw new Error(‘Reducer "‘ + key + ‘" returned undefined when probed with a random type. ‘ + (‘Don\‘t try to handle ‘ + _createStore.ActionTypes.INIT + ‘ or other actions in "redux/*" ‘) + ‘namespace. They are considered private. Instead, you must return the ‘ + ‘current state for any unknown actions, unless it is undefined, ‘ + ‘in which case you must return the initial state, regardless of the ‘ + ‘action type. The initial state may not be undefined.‘); 61 } 62 }); 63 } 64 81 function combineReducers(reducers) { 82 var reducerKeys = Object.keys(reducers); 83 var finalReducers = {}; 84 //过滤参数---把reducers里的方法放进finalReducers 85 for (var i = 0; i < reducerKeys.length; i++) { 86 var key = reducerKeys[i]; 87 if (typeof reducers[key] === ‘function‘) { 88 finalReducers[key] = reducers[key]; 89 } 90 } 91 var finalReducerKeys = Object.keys(finalReducers); 92 93 var sanityError; 94 try { 95 assertReducerSanity(finalReducers); 96 } catch (e) { 97 sanityError = e; 98 } 99 //把state,action分发给每一个reducer,并执行返回新的state,如果state没变化则返回原来的state 100 return function combination() { 101 var state = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; 102 var action = arguments[1]; 103 104 if (sanityError) { 105 throw sanityError; 106 } 107 108 if (true) { 109 var warningMessage = getUnexpectedStateShapeWarningMessage(state, finalReducers, action); 110 if (warningMessage) { 111 (0, _warning2["default"])(warningMessage); 112 } 113 } 114 115 var hasChanged = false; 116 var nextState = {}; 117 for (var i = 0; i < finalReducerKeys.length; i++) { 118 var key = finalReducerKeys[i]; 119 var reducer = finalReducers[key];//获取一个reducer方法 120 var previousStateForKey = state[key]; //获取上次的state 121 var nextStateForKey = reducer(previousStateForKey, action);//执行reducer 122 if (typeof nextStateForKey === ‘undefined‘) { 123 var errorMessage = getUndefinedStateErrorMessage(key, action); 124 throw new Error(errorMessage); 125 } 126 nextState[key] = nextStateForKey; 127 hasChanged = hasChanged || nextStateForKey !== previousStateForKey;//判断上次的state与现在的state是否相等 128 } 129 return hasChanged ? nextState : state; 130 }; 131 }
模块8:检测ie9以下的宿主对象,即dom与bom,就不上源码了
模块9:检测是否是对象
总结一下:
redux是不是很简单?就那么几个方法:createStore,subscribe,dispatch,getState,applyMiddleware,bindActionCreators,combineReducers。
createStore:创建store树;
createStore->subscribe:订阅事件,把监听的执行的方法放进来,其实就是一个数组;
createStore->dispatch:发布,执行所有的监听事件,且执行reducer更新state;
createStore->getState:获取state;
applyMiddleware:包装createStore与dispatch;
bindActionCreators:包装所有的action方法,给每个action包装一个dispatch方法,使执行action方法就会自动触发dispatch方法
combineReducers:合并多个reducer;
标签:
原文地址:http://www.cnblogs.com/dudeyouth/p/5391262.html