redux的源码解析

1、 redux出现的动机

1. Javascript 须要管理比任什么时候候都要多的state
2. state 在何时,因为什么缘由,如何变化已然不受控制。
3. 来自前端开发领域的新需求
4. 咱们老是将两个难以理清的概念混淆在一块儿:变化和异步。
5. Redux 视图让state 的变化变得可预测。前端

2、 核心概念

 1. 想要更新state中的数据,你须要发起一个action,Action就是一个普通的JavaScript 对象用来描述发生了什么。为了把actin 和state串起来开发一些函数,就是redcer。react

3、 三大原则

1. 单一数据源 整个应用的state被存储在一棵objecttree中, 而且这个 object tree 只 存在于一个惟一的store 中。webpack

2. state 是只读的,惟一改变state的方法就是触发action,action 是一个用于描述已发 生事件的普通对象。(确保了视图和网络请求不能直接修改state,只能表达想要修改的意图)git

3. 使用纯函数来执行修改成了描述action如何改变state tree ,你须要编写reducers。github

4、 源码解析

1. 入口文件index.js
import createStore from './createStore' import combineReducers from './combineReducers' import bindActionCreators from './bindActionCreators' import applyMiddleware from './applyMiddleware' import compose from './compose' import warning from './utils/warning' import __DO_NOT_USE__ActionTypes from './utils/actionTypes'

/* * This is a dummy function to check if the function name has been altered by minification. * If the function has been minified and NODE_ENV !== 'production', warn the user. */

// 判断文件是否被压缩了
function isCrushed() {} if ( process.env.NODE_ENV !== 'production' &&
  typeof isCrushed.name === 'string' && isCrushed.name !== 'isCrushed' ) { warning( 'You are currently using minified code outside of NODE_ENV === "production". ' +
      'This means that you are running a slower development build of Redux. ' +
      'You can use loose-envify (https://github.com/zertosh/loose-envify) for browserify ' +
      'or setting mode to production in webpack (https://webpack.js.org/concepts/mode/) ' +
      'to ensure you have the correct code for your production build.' ) } /* 从入口文件能够看出 redux 对外暴露了5个API。 createStore , combineReducers, bindActionCreators, applyMiddleware, compose, */ export { createStore, combineReducers, bindActionCreators, applyMiddleware, compose, __DO_NOT_USE__ActionTypes }
2. 对外暴露的第一个API createStore => createStore.js
 1 import $$observable from 'symbol-observable'
 2 
 3 import ActionTypes from './utils/actionTypes'
 4 import isPlainObject from './utils/isPlainObject'
 5 
 6 /**  7  * Creates a Redux store that holds the state tree.  8  * The only way to change the data in the store is to call `dispatch()` on it.  9  *  10  * There should only be a single store in your app. To specify how different  11  * parts of the state tree respond to actions, you may combine several reducers  12  * into a single reducer function by using `combineReducers`.  13  *  14  * @param {Function} reducer A function that returns the next state tree, given  15  * the current state tree and the action to handle.  16  *  17  * @param {any} [preloadedState] The initial state. You may optionally specify it  18  * to hydrate the state from the server in universal apps, or to restore a  19  * previously serialized user session.  20  * If you use `combineReducers` to produce the root reducer function, this must be  21  * an object with the same shape as `combineReducers` keys.  22  *  23  * @param {Function} [enhancer] The store enhancer. You may optionally specify it  24  * to enhance the store with third-party capabilities such as middleware,  25  * time travel, persistence, etc. The only store enhancer that ships with Redux  26  * is `applyMiddleware()`.  27  *  28  * @returns {Store} A Redux store that lets you read the state, dispatch actions  29  * and subscribe to changes.  30  */
 31 /*
 32  从源码上能够看出 createStore 是一个函数。接收三个参数 reducer, preloadeState, enhancer  33  */
 34 export default function createStore(reducer, preloadedState, enhancer) {  35   // 若是 preloadeState 是一个函数 && enhancer未定义preloadeState 和 enhancer交换位置
 36   if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {  37     enhancer = preloadedState  38     preloadedState = undefined  39  }  40   //  41   if (typeof enhancer !== 'undefined') {  42     if (typeof enhancer !== 'function') {  43       throw new Error('Expected the enhancer to be a function.')  44  }  45     // 上面两个判断是为了确保 enchancer是个函数
 46     return enhancer(createStore)(reducer, preloadedState)  47  }  48 
 49   // reducer必须是 个函数,若是不是个函数给出友好的 提示
 50   if (typeof reducer !== 'function') {  51     throw new Error('Expected the reducer to be a function.')  52  }  53 
 54   let currentReducer = reducer    // 把reducer 暂存起来
 55   let currentState = preloadedState // 把preloadeState暂存起来
 56   let currentListeners = []  57   let nextListeners = currentListeners  58   let isDispatching = false   //判断是否正处于dispatch中
 59 
 60   // 若是 nextListeners 和 currrentListeners 都指向一个内存空间的时候, 深复制一份出来。确保两个之间不会相互影响。
 61   function ensureCanMutateNextListeners() {  62     if (nextListeners === currentListeners) {  63       nextListeners = currentListeners.slice()  64  }  65  }  66 
 67   /**  68  * Reads the state tree managed by the store.  69  *  70  * @returns {any} The current state tree of your application.  71    */
 72   // 获取目前的 state的值。
 73   function getState() {  74     if (isDispatching) {  75       throw new Error(  76         'You may not call store.getState() while the reducer is executing. ' +
 77           'The reducer has already received the state as an argument. ' +
 78           'Pass it down from the top reducer instead of reading it from the store.'
 79  )  80  }  81 
 82     return currentState  83  }  84 
 85   /**  86  * Adds a change listener. It will be called any time an action is dispatched,  87  * and some part of the state tree may potentially have changed. You may then  88  * call `getState()` to read the current state tree inside the callback.  89  *  90  * You may call `dispatch()` from a change listener, with the following  91  * caveats:  92  *  93  * 1. The subscriptions are snapshotted just before every `dispatch()` call.  94  * If you subscribe or unsubscribe while the listeners are being invoked, this  95  * will not have any effect on the `dispatch()` that is currently in progress.  96  * However, the next `dispatch()` call, whether nested or not, will use a more  97  * recent snapshot of the subscription list.  98  *  99  * 2. The listener should not expect to see all state changes, as the state 100  * might have been updated multiple times during a nested `dispatch()` before 101  * the listener is called. It is, however, guaranteed that all subscribers 102  * registered before the `dispatch()` started will be called with the latest 103  * state by the time it exits. 104  * 105  * @param {Function} listener A callback to be invoked on every dispatch. 106  * @returns {Function} A function to remove this change listener. 107    */
108   // 经典的订阅函数
109   function subscribe(listener) { 110     if (typeof listener !== 'function') { 111       throw new Error('Expected the listener to be a function.') 112  } 113 
114     if (isDispatching) { 115       throw new Error( 116         'You may not call store.subscribe() while the reducer is executing. ' +
117           'If you would like to be notified after the store has been updated, subscribe from a ' +
118           'component and invoke store.getState() in the callback to access the latest state. ' +
119           'See https://redux.js.org/api-reference/store#subscribe(listener) for more details.'
120  ) 121  } 122     // 闭包的经典应用 每次订阅一个事件的时候,都有一个内部状态, 用于后续的取消订阅
123     let isSubscribed = true
124     // 深复制一份监听对象
125  ensureCanMutateNextListeners() 126     // 把每一个监听对象都放置于一个数组中,保存下来,(精华之处,对闭包的使用登峰造极)
127  nextListeners.push(listener) 128     // 当注册一个监听事件的返回一个函数,调用这个函数能够取消订阅,具体操做方法就是从监听的数组中移出掉。
129     return function unsubscribe() { 130       // 防止重复取消订阅
131       if (!isSubscribed) { 132         return
133  } 134 
135       if (isDispatching) { 136         throw new Error( 137           'You may not unsubscribe from a store listener while the reducer is executing. ' +
138             'See https://redux.js.org/api-reference/store#subscribe(listener) for more details.'
139  ) 140  } 141       // 对应上面那条,防止重复取消订阅
142       isSubscribed = false
143 
144  ensureCanMutateNextListeners() 145       const index = nextListeners.indexOf(listener) 146         // 删除数组中某一项的方法 splice
147       nextListeners.splice(index, 1) 148  } 149  } 150 
151   /** 152  * Dispatches an action. It is the only way to trigger a state change. 153  * 154  * The `reducer` function, used to create the store, will be called with the 155  * current state tree and the given `action`. Its return value will 156  * be considered the **next** state of the tree, and the change listeners 157  * will be notified. 158  * 159  * The base implementation only supports plain object actions. If you want to 160  * dispatch a Promise, an Observable, a thunk, or something else, you need to 161  * wrap your store creating function into the corresponding middleware. For 162  * example, see the documentation for the `redux-thunk` package. Even the 163  * middleware will eventually dispatch plain object actions using this method. 164  * 165  * @param {Object} action A plain object representing “what changed”. It is 166  * a good idea to keep actions serializable so you can record and replay user 167  * sessions, or use the time travelling `redux-devtools`. An action must have 168  * a `type` property which may not be `undefined`. It is a good idea to use 169  * string constants for action types. 170  * 171  * @returns {Object} For convenience, the same action object you dispatched. 172  * 173  * Note that, if you use a custom middleware, it may wrap `dispatch()` to 174  * return something else (for example, a Promise you can await). 175    */
176   // 派发一个事件
177   function dispatch(action) { 178     // p、判断action是不是个对象
179     if (!isPlainObject(action)) { 180       throw new Error( 181         'Actions must be plain objects. ' +
182           'Use custom middleware for async actions.'
183  ) 184  } 185     // 严格控制 action 的书写格式 { type: 'INCREMENT'}
186     if (typeof action.type === 'undefined') { 187       throw new Error( 188         'Actions may not have an undefined "type" property. ' +
189           'Have you misspelled a constant?'
190  ) 191  } 192 
193     if (isDispatching) { 194       throw new Error('Reducers may not dispatch actions.') 195  } 196     // isDipatching 也是闭包的经典用法
197       /*
198  触发 dispatch的时候 把 isDispatching 改成 true。 照应全篇中对 dispatching 正在触发的时候的判断 199  finally 执行完毕的时候 置为 false 200        */
201     try { 202       isDispatching = true
203       // 获取最新 的state 值。 currentState 经典之处闭包
204       currentState = currentReducer(currentState, action) 205     } finally { 206       isDispatching = false
207  } 208 
209     // 对监听对象重新赋值 其实里面每一个listener都是一个函数。 于subscribe相对应
210     // 当每发生一个dispatch 事件的时候, 都循环调用,触发监听事件
211     const listeners = (currentListeners = nextListeners) 212     for (let i = 0; i < listeners.length; i++) { 213       const listener = listeners[i] 214  listener() 215  } 216 
217     return action 218  } 219 
220   /** 221  * Replaces the reducer currently used by the store to calculate the state. 222  * 223  * You might need this if your app implements code splitting and you want to 224  * load some of the reducers dynamically. You might also need this if you 225  * implement a hot reloading mechanism for Redux. 226  * 227  * @param {Function} nextReducer The reducer for the store to use instead. 228  * @returns {void} 229    */
230   // 替换 reducer 用 新的 reducer替换之前的reducer 参数一样必须是函数
231   function replaceReducer(nextReducer) { 232     if (typeof nextReducer !== 'function') { 233       throw new Error('Expected the nextReducer to be a function.') 234  } 235 
236     currentReducer = nextReducer 237  dispatch({ type: ActionTypes.REPLACE }) 238  } 239 
240   /** 241  * Interoperability point for observable/reactive libraries. 242  * @returns {observable} A minimal observable of state changes. 243  * For more information, see the observable proposal: 244  * https://github.com/tc39/proposal-observable 245    */
246   // 观察模式
247   function observable() { 248     const outerSubscribe = subscribe 249     return { 250       /** 251  * The minimal observable subscription method. 252  * @param {Object} observer Any object that can be used as an observer. 253  * The observer object should have a `next` method. 254  * @returns {subscription} An object with an `unsubscribe` method that can 255  * be used to unsubscribe the observable from the store, and prevent further 256  * emission of values from the observable. 257        */
258  subscribe(observer) { 259         if (typeof observer !== 'object' || observer === null) { 260           throw new TypeError('Expected the observer to be an object.') 261  } 262 
263         function observeState() { 264           if (observer.next) { 265  observer.next(getState()) 266  } 267  } 268 
269  observeState() 270         const unsubscribe = outerSubscribe(observeState) 271         return { unsubscribe } 272  }, 273 
274  [$$observable]() { 275         return this
276  } 277  } 278  } 279 
280   // When a store is created, an "INIT" action is dispatched so that every
281   // reducer returns their initial state. This effectively populates
282   // the initial state tree.
283     // 触发一state 树
284  dispatch({ type: ActionTypes.INIT }) 285   /*
286  由此能够看出 调用 createStore(); 后。对外暴露的方法 287  1. dispatch 288  2. subscribe 289  3. getState 290  4. replaceReducer 291  5.观察模式 292  const store = createStore(reducer, preloadedState, enchancer); 293  store.dispatch(action); 294  store.getState(); // 为何这个方法可以得到 state的值。由于 currentState 的闭包实现。 295  store.subscribe(() => console.log(store.getState())); 296  store.replaceReducer(reducer); 297  总结:纵观createStore方法的实现,其实都是创建在闭包的基础之上。可谓是把闭包用到了极致。 298    */
299   return { 300  dispatch, 301  subscribe, 302  getState, 303  replaceReducer, 304  [$$observable]: observable 305  } 306 }
3. combineReducers.js
 1 import ActionTypes from './utils/actionTypes'
 2 import warning from './utils/warning'
 3 import isPlainObject from './utils/isPlainObject'
 4 
 5 function getUndefinedStateErrorMessage(key, action) {  6   const actionType = action && action.type  7   const actionDescription =
 8     (actionType && `action "${String(actionType)}"`) || 'an action'
 9 
 10   return (  11     `Given ${actionDescription}, reducer "${key}" returned undefined. ` +
 12     `To ignore an action, you must explicitly return the previous state. ` +
 13     `If you want this reducer to hold no value, you can return null instead of undefined.`  14  )  15 }  16 
 17 function getUnexpectedStateShapeWarningMessage(  18  inputState,  19  reducers,  20  action,  21  unexpectedKeyCache  22 ) {  23   const reducerKeys = Object.keys(reducers)  24   const argumentName =
 25     action && action.type === ActionTypes.INIT  26       ? 'preloadedState argument passed to createStore'
 27       : 'previous state received by the reducer'
 28 
 29   if (reducerKeys.length === 0) {  30     return (  31       'Store does not have a valid reducer. Make sure the argument passed ' +
 32       'to combineReducers is an object whose values are reducers.'
 33  )  34  }  35 
 36   if (!isPlainObject(inputState)) {  37     return (  38       `The ${argumentName} has unexpected type of "` +  39  {}.toString.call(inputState).match(/\s([a-z|A-Z]+)/)[1] +  40       `". Expected argument to be an object with the following ` +
 41       `keys: "${reducerKeys.join('", "')}"`  42  )  43  }  44 
 45   const unexpectedKeys = Object.keys(inputState).filter(  46     key => !reducers.hasOwnProperty(key) && !unexpectedKeyCache[key]  47  )  48 
 49   unexpectedKeys.forEach(key => {  50     unexpectedKeyCache[key] = true
 51  })  52 
 53   if (action && action.type === ActionTypes.REPLACE) return
 54 
 55   if (unexpectedKeys.length > 0) {  56     return (  57       `Unexpected ${unexpectedKeys.length > 1 ? 'keys' : 'key'} ` +
 58       `"${unexpectedKeys.join('", "')}" found in ${argumentName}. ` +
 59       `Expected to find one of the known reducer keys instead: ` +
 60       `"${reducerKeys.join('", "')}". Unexpected keys will be ignored.`  61  )  62  }  63 }  64 
 65 function assertReducerShape(reducers) {  66   Object.keys(reducers).forEach(key => {  67     const reducer = reducers[key]  68     const initialState = reducer(undefined, { type: ActionTypes.INIT })  69 
 70     if (typeof initialState === 'undefined') {  71       throw new Error(  72         `Reducer "${key}" returned undefined during initialization. ` +
 73           `If the state passed to the reducer is undefined, you must ` +
 74           `explicitly return the initial state. The initial state may ` +
 75           `not be undefined. If you don't want to set a value for this reducer, ` +  76  `you can use null instead of undefined.`  77  )  78  }  79 
 80  if (  81  typeof reducer(undefined, {  82  type: ActionTypes.PROBE_UNKNOWN_ACTION()  83       }) === 'undefined'
 84  ) {  85  throw new Error(  86  `Reducer "${key}" returned undefined when probed with a random type. ` +  87           `Don't try to handle ${  88  ActionTypes.INIT  89           } or other actions in "redux/*" ` +
 90           `namespace. They are considered private. Instead, you must return the ` +
 91           `current state for any unknown actions, unless it is undefined, ` +
 92           `in which case you must return the initial state, regardless of the ` +
 93           `action type. The initial state may not be undefined, but can be null.`  94  )  95  }  96  })  97 }  98 
 99 /** 100  * Turns an object whose values are different reducer functions, into a single 101  * reducer function. It will call every child reducer, and gather their results 102  * into a single state object, whose keys correspond to the keys of the passed 103  * reducer functions. 104  * 105  * @param {Object} reducers An object whose values correspond to different 106  * reducer functions that need to be combined into one. One handy way to obtain 107  * it is to use ES6 `import * as reducers` syntax. The reducers may never return 108  * undefined for any action. Instead, they should return their initial state 109  * if the state passed to them was undefined, and the current state for any 110  * unrecognized action. 111  * 112  * @returns {Function} A reducer function that invokes every reducer inside the 113  * passed object, and builds a state object with the same shape. 114  */
115 
116 /*
117  combineReducers 顾名思义就是合并reduces的一个方法。 118  1. 为了项目便于维护与管理咱们就须要拆按模块拆分reducers。 119  2. 而combineReducers就是为了解决这个的问题的。 120 
121  */
122 export default function combineReducers(reducers) { // 参数reducers 是一个对象
123   const reducerKeys = Object.keys(reducers) // 获取reducers的k
124   const finalReducers = {} 125   for (let i = 0; i < reducerKeys.length; i++) { 126     const key = reducerKeys[i] 127 
128     if (process.env.NODE_ENV !== 'production') { 129       if (typeof reducers[key] === 'undefined') { 130         warning(`No reducer provided for key "${key}"`) 131  } 132  } 133 
134     // 深复制一份reducers出来, 防止后续操做出现不可控因素
135     if (typeof reducers[key] === 'function') { 136       finalReducers[key] = reducers[key] 137  } 138  } 139   const finalReducerKeys = Object.keys(finalReducers) 140 
141  let unexpectedKeyCache 142   if (process.env.NODE_ENV !== 'production') { 143     unexpectedKeyCache = {} 144  } 145 
146  let shapeAssertionError 147   try { 148  assertReducerShape(finalReducers) 149   } catch (e) { 150     shapeAssertionError = e 151  } 152   // 闭包的运用, 把合并的 reducer保存下来。
153   return function combination(state = {}, action) { 154     if (shapeAssertionError) { 155       throw shapeAssertionError 156  } 157 
158     if (process.env.NODE_ENV !== 'production') { 159       const warningMessage = getUnexpectedStateShapeWarningMessage( 160  state, 161  finalReducers, 162  action, 163  unexpectedKeyCache 164  ) 165       if (warningMessage) { 166  warning(warningMessage) 167  } 168  } 169 
170     let hasChanged = false
171     const nextState = {} 172     for (let i = 0; i < finalReducerKeys.length; i++) { 173       const key = finalReducerKeys[i] 174       const reducer = finalReducers[key] 175       const previousStateForKey = state[key] 176       // 把合并的时候的key值做为Key值为标准。 在循环遍历的时候取出对应的 reducers 触发 reducer函数。
177       /*
178  其实对应的createStore.js中的 179  try { 180  isDispatching = true 181  // 获取最新 的state 值。 currentState 经典之处闭包 182  currentState = currentReducer(currentState, action) 183  } finally { 184  isDispatching = false 185  } 186        */
187       const nextStateForKey = reducer(previousStateForKey, action) 188       if (typeof nextStateForKey === 'undefined') { 189         const errorMessage = getUndefinedStateErrorMessage(key, action) 190         throw new Error(errorMessage) 191  } 192       nextState[key] = nextStateForKey 193       hasChanged = hasChanged || nextStateForKey !== previousStateForKey 194  } 195     return hasChanged ? nextState : state 196  } 197 } 198 /** 199  * 使用方法 200  * const reducers = combineReducers({ reducer1, reducer2 }); 201  * const store = createStore(reducers, preloadedState, enchancer); 202  */
4. bindActionCreators.js
 1 // 主要这个函数
 2 function bindActionCreator(actionCreator, dispatch) {  3   return function() {  4     return dispatch(actionCreator.apply(this, arguments))  5  }  6 }  7 
 8 /**  9  * Turns an object whose values are action creators, into an object with the 10  * same keys, but with every function wrapped into a `dispatch` call so they 11  * may be invoked directly. This is just a convenience method, as you can call 12  * `store.dispatch(MyActionCreators.doSomething())` yourself just fine. 13  * 14  * For convenience, you can also pass a single function as the first argument, 15  * and get a function in return. 16  * 17  * @param {Function|Object} actionCreators An object whose values are action 18  * creator functions. One handy way to obtain it is to use ES6 `import * as` 19  * syntax. You may also pass a single function. 20  * 21  * @param {Function} dispatch The `dispatch` function available on your Redux 22  * store. 23  * 24  * @returns {Function|Object} The object mimicking the original object, but with 25  * every action creator wrapped into the `dispatch` call. If you passed a 26  * function as `actionCreators`, the return value will also be a single 27  * function. 28  */
29 
30 /*
31  接受两个参数,一个action creator, 一个是 value的 action creator的对象。 32  dispatch 。 一个由 Store 实列 提供的dispatch的函数。 看createStore.js源码就能够作知道其中原理。 33  */
34 export default function bindActionCreators(actionCreators, dispatch) { 35   if (typeof actionCreators === 'function') { 36     return bindActionCreator(actionCreators, dispatch) 37  } 38 
39   if (typeof actionCreators !== 'object' || actionCreators === null) { 40     throw new Error( 41       `bindActionCreators expected an object or a function, instead received ${ 42         actionCreators === null ? 'null' : typeof actionCreators 43       }. ` +
44         `Did you write "import ActionCreators from" instead of "import * as ActionCreators from"?` 45  ) 46  } 47 
48   const keys = Object.keys(actionCreators) 49   const boundActionCreators = {} 50   for (let i = 0; i < keys.length; i++) { 51     const key = keys[i] 52     const actionCreator = actionCreators[key] 53     if (typeof actionCreator === 'function') { 54       boundActionCreators[key] = bindActionCreator(actionCreator, dispatch) 55  } 56  } 57   /*
58  一个与原对象相似的对象,只不过这个对象的 value 都是会直接 dispatch 原 action creator 返回的结果的函数。 59  若是传入一个单独的函数做为 actionCreators,那么返回的结果也是一个单独的函数。 60  原本触发 action 的方法是 store.dispatch(action); 61  通过这个方法封装后 能够直接调用函数名字 62  aa('参数'); 63    */
64   return boundActionCreators 65 }

5. applyMiddleware.js  在redux 中最难理解的一个函数。web

import compose from './compose' import createStore from "./createStore"; /** * Creates a store enhancer that applies middleware to the dispatch method * of the Redux store. This is handy for a variety of tasks, such as expressing * asynchronous actions in a concise manner, or logging every action payload. * * See `redux-thunk` package as an example of the Redux middleware. * * 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. * * @param {...Function} middlewares The middleware chain to be applied. * @returns {Function} A store enhancer applying the middleware. */
// 经过看源码知道 applyMiddleware返回一个高阶函数。 /* applyMiddleware的使用地方 const store = createStore(reducer,{}, applyMiddleware(...middlewares)); 由此能够看出 applyMiddlewares 的使用方法主要是和 createStore.js 中 createStore方法的第三个参数对应。翻开源码 if (typeof enhancer !== 'undefined') { if (typeof enhancer !== 'function') { throw new Error('Expected the enhancer to be a function.') } // 上面两个判断是为了确保 enchancer是个函数 return enhancer(createStore)(reducer, preloadedState) } */ export default function applyMiddleware(...middlewares) { // createSotre 中 的第三个参数 enhancer
  return createStore => (...args) => { // 经过对应的代码能够发现其实 ...aregs 对应的是 reducer, preloadedState
    const store = createStore(...args) let dispatch = () => { throw new Error( `Dispatching while constructing your middleware is not allowed. ` + `Other middleware would not be applied to this dispatch.` ) } // 定义中间件必须知足的条件。 API getState, dispatch();
    const middlewareAPI = { getState: store.getState, dispatch: (...args) => dispatch(...args) } const chain = middlewares.map(middleware => middleware(middlewareAPI)) /** * export default function compose(...funcs) { if (funcs.length === 0) { return arg => arg } if (funcs.length === 1) { return funcs[0] } return funcs.reduce((a, b) => (...args) => a(b(...args))) } compose函数 主要是 利用数组 reducer 方法对参数的处理。 */ dispatch = compose(...chain)(store.dispatch) // 经过这个返回值咱们能够知道 在createStore.js中enchancer的返回值。
    return { ...store, dispatch } } } /** * applyMiddlewares函数比较难理解。 多看几个中间件,好比 logger 和 redux-thunk 等。对该方法可以更深的理解。 */

5、 redux的总结

经过阅读redux的源码,印象最深的就是如何手动写个订阅模式,数据改变的时候,如何触发全部监听事件。闭包的运用登峰造极。其中最难的两个函数 applyMiddlewares 和compose.js 还须要细细体会。没有真正领悟到其精华之处。express

谢谢你们。redux

相关文章
相关标签/搜索