createStore
function (
reducer: Reducer<S, A>,
preloadedState?: PreloadedState<S> | StoreEnhancer<Ext, StateExt>,
enhancer?: StoreEnhancer<Ext, StateExt>
){
if (
(typeof preloadedState === 'function' && typeof enhancer === 'function') ||
(typeof enhancer === 'function' && typeof arguments[3] === 'function')
) {
throw new Error(
'It looks like you are passing several store enhancers to ' +
'createStore(). This is not supported. Instead, compose them ' +
'together to a single function.'
)
}
if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
enhancer = preloadedState as StoreEnhancer<Ext, StateExt>
preloadedState = undefined
}
if (typeof enhancer !== 'undefined') {
if (typeof enhancer !== 'function') {
throw new Error('Expected the enhancer to be a function.')
}
return enhancer(createStore)(
reducer,
preloadedState as PreloadedState<S>
) as Store<ExtendState<S, StateExt>, A, StateExt, Ext> & Ext
}
if (typeof reducer !== 'function') {
throw new Error('Expected the reducer to be a function.')
}
let currentReducer = reducer
let currentState = preloadedState as S
let currentListeners: (() => void)[] | null = []
let nextListeners = currentListeners
let isDispatching = false
function getState() {
if (isDispatching) {
throw new Error(
'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
}
function subscribe ...
function dispatch...
function replaceReducer...
// 初始化state
dispatch({ type: ActionTypes.REPLACE } as A)
const store = ({
dispatch: dispatch as Dispatch<A>,
subscribe,
getState,
replaceReducer,
[$$observable]: observable
}
return store
}
做一些不符合规则的参数,如果初始化state是函数,并且enhancer没有定义,那就认为初始化State是undefined,enchance是第二个参数。如果enhancer是个函数那不是立马调用createStore,转交给enhancer去createStore enhancer(createStore)(reducer,preloadedState as PreloadedState<S>)
。
初始化state = currentState
,如果调用getState()
其实返回的是currentState。初始化会dispatch({ type:xx })
也就是说,你可以不必传initialState这个额外的参数,只需要在reducers里面指定。type不中标的return值。
dispatch
function dispatch(action) {
// 判断action对象
if (!isPlainObject(action)) {
throw new Error('Actions must be plain objects. ' + 'Use custom middleware for async actions.');
}
// 判断action type
if (typeof action.type === 'undefined') {
throw new Error('Actions may not have an undefined "type" property. ' + 'Have you misspelled a constant?');
}
if (isDispatching) {
throw new Error('Reducers may not dispatch actions.');
}
try {
isDispatching = true;
// 执行reducer
currentState = currentReducer(currentState, action);
} finally {
isDispatching = false;
}
// 执行subscribe监听器
// store.subscribe(() => store.getState() // state是最新的state)
var listeners = currentListeners = nextListeners;
for (var i = 0; i < listeners.length; i++) {
var listener = listeners[i];
listener();
}
return action;
}
dispatch 触发一个action,首先,判断action是否为对象,判断action的type,其次判断isDispatching
(这是一个flag,防止dispatch的reducer的时候,触发另外一个reducers,redux限制reducers同时只能触发一个)。
接下来,执行reducer函数。最后去执行subscribe监听器,注意这时候subscribe监听器可以拿到最新的state,也就是说store.subscribe(() => console.log(store.getState()) )
,当前这个console是reducers改变state之后最新的值。
combineReducers
假设我们目前有combineReducers(reducer1,reducer2),如果我们要dispatch({ type: xxx })
,那么reducer1,和reducer2哪个会执行?答案是:都会执行。
function combineReducers(reducers) {
var reducerKeys = Object.keys(reducers);
var finalReducers = {};
for (var i = 0; i < reducerKeys.length; i++) {
var key = reducerKeys[i];
{
if (typeof reducers[key] === 'undefined') {
warning("No reducer provided for key \"" + key + "\"");
}
}
if (typeof reducers[key] === 'function') {
finalReducers[key] = reducers[key];
}
}
var finalReducerKeys = Object.keys(finalReducers); // This is used to make sure we don't warn about the same
// keys multiple times.
var unexpectedKeyCache;
{
unexpectedKeyCache = {};
}
var shapeAssertionError;
try {
assertReducerShape(finalReducers);
} catch (e) {
shapeAssertionError = e;
}
return function combination....
assertReducerShape
,dispatch 一个action,type为INIT和UNLNOW_ACTION,获取初始值,判断初始值不为空
getUnexpectedStateShapeWarningMessage
,1 判断reducers是否存在一个及以上。 2 判断state为一个对象。 3 判断state对应的key有响应的reducers处理
function combination(state, action) {
if (state === void 0) {
state = {};
}
if (shapeAssertionError) {
throw shapeAssertionError;
}
{
var warningMessage = getUnexpectedStateShapeWarningMessage(state,
finalReducers, action, unexpectedKeyCache);
if (warningMessage) {
warning(warningMessage);
}
}
var hasChanged = false;
var nextState = {};
for (var _i = 0; _i < finalReducerKeys.length; _i++) {
var _key = finalReducerKeys[_i];
var reducer = finalReducers[_key];
var previousStateForKey = state[_key];
var nextStateForKey = reducer(previousStateForKey, action);
if (typeof nextStateForKey === 'undefined') {
var errorMessage = getUndefinedStateErrorMessage(_key, action);
throw new Error(errorMessage);
}
nextState[_key] = nextStateForKey;
hasChanged = hasChanged || nextStateForKey !== previousStateForKey;
}
hasChanged = hasChanged || finalReducerKeys.length !== Object.keys(state).length;
return hasChanged ? nextState : state;
};
combination
combineReducers最核心部分,combineReducers的返回值,首先从参数上去看就combination就是一个reducers。
当你执行一个dispatch(action)时,这个action会在每个模块reducers里面执行一次,2个重要的变量nextStateForKey
(执行reducers后的state),previousStateForKey
当前模块的state。
这里有一个非常重要的flag,hasChanged,hasChange初始值是false,当执行完reducers之后,会去判断对象的浅比较,如果nextStateForKey
与previousStateForKey
不是同一个,则hasChange为true,返回值为更新的state即currentState = nextStateForKey。
Enhancer & Middleware
compose
export default function compose(...funcs: Function[]) {
if (funcs.length === 0) {
// infer the argument type so it is usable in inference down the line
return <T>(arg: T) => arg
}
if (funcs.length === 1) {
return funcs[0]
}
return funcs.reduce((a, b) => (...args: any) => a(b(...args)))
}
// 看起来很绕,翻译成人话就是
function compose(...params) {
let result = params.shift()
params.forEach((current) => {
let prev = result
result = (...args) => {
return current(prev(...args))
}
})
return result
}
相当于compose(funcA, funcB, funcC) 形象为 compose(funcA(funcB(funcC()))
,这一层看起来还好理解,但是在Redux
里面这个是非常绕的,虽然compose
成了一个新的洋葱形函数,但是如果compose(funcA(funcB(funcC()))(1)(2)
,这样子的话是特别绕的因为新的函数compose(funcA(funcB(funcC()))
执行后,返回值又是一个函数newCompose
,那么这个函数再执行轨迹就是完全倒过来的。
applyMiddleware
如果我们正常写一个middleware是怎么样的:
function log({ getState, dispatch }) {
console.log(1)
return (next) => {
console.log(2)
return action => {
console.log(action.type)
next(action)
}
}
}
getState,和dispatch自然不必多说,next就是调用下一个函数。
初始化:第一次执行:初始化getState dispatch,第二次执行,初始化next的指向。等到调用action函数的时候才是dispatch真正的执行路径。
export default function applyMiddleware(
...middlewares: Middleware[]
): StoreEnhancer<any> {
return (createStore: StoreCreator) => <S, A extends AnyAction>(
reducer: Reducer<S, A>,
...args: any[]
) => {
const store = createStore(reducer, ...args)
let dispatch: Dispatch = () => {
throw new Error(
'Dispatching while constructing your middleware is not allowed. ' +
'Other middleware would not be applied to this dispatch.'
)
}
const middlewareAPI: MiddlewareAPI = {
getState: store.getState,
dispatch: (action, ...args) => dispatch(action, ...args)
}
const chain = middlewares.map(middleware => middleware(middlewareAPI))
dispatch = compose<typeof dispatch>(...chain)(store.dispatch)
return {
...store,
dispatch
}
}
}
这里分2个逻辑,一个createStore
,一个是compose。createStore
上述createStore
函数有提到,enhancer为函数时,不直接初始化,而是丢给下面的enhancer
函数。
接下来初始化middlewareAPI。把传入的middlewares合成一个chain,并且保存middlewareAPI。接着,改变dispatch的指向,dispatch变成middleware compose,真正的dispatch作为最后middleware的next传入进去。
这部分比较绕,可以看一下流程图:
顺便可以参考一下这里伪代码
以上,redux核心代码都分析完。百行代码千行文档,redux绕在他定的一些概念性的东西,只要理解了,也不难。