// 这是执行的第一个用于抛错的函数 functionassertReducerShape(reducers) { // 将 combineReducers 中的参数遍历 Object.keys(reducers).forEach((key) => { const reducer = reducers[key]; // 给他传入一个 action const initialState = reducer(undefined, { type: ActionTypes.INIT }); // 如果得到的 state 为 undefined 就抛错 if (typeof initialState === 'undefined') { thrownewError( `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. If you don't want to set a value for this reducer, ` + `you can use null instead of undefined.` ); } // 再过滤一次,考虑到万一你在 reducer 中给 ActionTypes.INIT 返回了值 // 传入一个随机的 action 判断值是否为 undefined const type = '@@redux/PROBE_UNKNOWN_ACTION_' + Math.random().toString(36).substring(7).split('').join('.'); if (typeof reducer(undefined, { type }) === 'undefined') { thrownewError( `Reducer "${key}" returned undefined when probed with a random type. ` + `Don't try to handle ${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, but can be null.` ); } }); }
functiongetUnexpectedStateShapeWarningMessage( inputState, reducers, action, unexpectedKeyCache ) { // 这里的 reducers 已经是 finalReducers const reducerKeys = Object.keys(reducers); const argumentName = action && action.type === ActionTypes.INIT ? 'preloadedState argument passed to createStore' : 'previous state received by the reducer';
// 如果 finalReducers 为空 if (reducerKeys.length === 0) { return ( 'Store does not have a valid reducer. Make sure the argument passed ' + 'to combineReducers is an object whose values are reducers.' ); } // 如果你传入的 state 不是对象 if (!isPlainObject(inputState)) { 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('", "')}"` ); } // 将参入的 state 于 finalReducers 下的 key 做比较,过滤出多余的 key const unexpectedKeys = Object.keys(inputState).filter( (key) => !reducers.hasOwnProperty(key) && !unexpectedKeyCache[key] );
if (action && action.type === ActionTypes.REPLACE) return;
// 如果 unexpectedKeys 有值的话 if (unexpectedKeys.length > 0) { 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.` ); } }
// 这个没啥好说的,就是把当前的 state 返回,但是当正在执行 reducer 时不能执行该方法 functiongetState() { if (isDispatching) { thrownewError( 'You may not call store.getState() while the reducer is executing. ' + 'The reducer has already received the state as an argument. ' + 'Pass it down from the top reducer instead of reading it from the store.' ); }
return currentState; } // 接收一个函数参数 functionsubscribe(listener) { if (typeof listener !== 'function') { thrownewError('Expected listener to be a function.'); } // 这部分最主要的设计 nextListeners 已经讲过,其他基本没什么好说的 if (isDispatching) { thrownewError( 'You may not call store.subscribe() while the reducer is executing. ' + 'If you would like to be notified after the store has been updated, subscribe from a ' + 'component and invoke store.getState() in the callback to access the latest state. ' + 'See http://redux.js.org/docs/api/Store.html#subscribe for more details.' ); }
// 返回一个取消订阅函数 returnfunctionunsubscribe() { if (!isSubscribed) { return; }
if (isDispatching) { thrownewError( 'You may not unsubscribe from a store listener while the reducer is executing. ' + 'See http://redux.js.org/docs/api/Store.html#subscribe for more details.' ); }
isSubscribed = false;
ensureCanMutateNextListeners(); const index = nextListeners.indexOf(listener); nextListeners.splice(index, 1); }; }
functiondispatch(action) { // 原生的 dispatch 会判断 action 是否为对象 if (!isPlainObject(action)) { thrownewError( 'Actions must be plain objects. ' + 'Use custom middleware for async actions.' ); }
if (typeof action.type === 'undefined') { thrownewError( 'Actions may not have an undefined "type" property. ' + 'Have you misspelled a constant?' ); } // 注意在 Reducers 中是不能执行 dispatch 函数的 // 因为你一旦在 reducer 函数中执行 dispatch,会引发死循环 if (isDispatching) { thrownewError('Reducers may not dispatch actions.'); } // 执行 combineReducers 组合后的函数 try { isDispatching = true; currentState = currentReducer(currentState, action); } finally { isDispatching = false; } // 然后遍历 currentListeners,执行数组中保存的函数 const listeners = (currentListeners = nextListeners); for (let i = 0; i < listeners.length; i++) { const listener = listeners[i]; listener(); }