You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
if(typeofenhancer!=='undefined'){if(typeofenhancer!=='function'){thrownewError('Expected the enhancer to be a function.')}returnenhancer(createStore)(reducer,preloadedState)}
functiondispatch(action){if(typeofaction.type==='undefined'){thrownewError('Actions may not have an undefined "type" property. '+'Have you misspelled a constant?')}if(isDispatching){// 如果正在 dispatch,再次触发 dispatch,则报错thrownewError('Reducers may not dispatch actions.')}try{isDispatching=true// 表示正在执行 `dispatch`currentState=currentReducer(currentState,action)// 执行最新的 Reducer,返回最新的 state}finally{isDispatching=false}constlisteners=(currentListeners=nextListeners)// 每次 dispatch 执行,订阅者都会执行for(leti=0;i<listeners.length;i++){constlistener=listeners[i]listener()}returnaction}
functionsubscribe(listener){if(typeoflistener!=='function'){// 订阅者必须是函数thrownewError('Expected the listener to be a function.')}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 https://redux.js.org/api-reference/store#subscribe(listener) for more details.')}letisSubscribed=truenextListeners.push(listener)// 订阅消息,每次 dispatch(action) 时候,订阅者都会接受到消息returnfunctionunsubscribe(){// 返回取消订阅方法if(!isSubscribed){return}if(isDispatching){thrownewError('You may not unsubscribe from a store listener while the reducer is executing. '+'See https://redux.js.org/api-reference/store#subscribe(listener) for more details.')}isSubscribed=falseconstindex=nextListeners.indexOf(listener)nextListeners.splice(index,1)// 取消订阅者}}
functionobservable(){constouterSubscribe=subscribereturn{subscribe(observer){if(typeofobserver!=='object'||observer===null){thrownewTypeError('Expected the observer to be an object.')}functionobserveState(){if(observer.next){observer.next(getState())// 对 currentState 进行监听}}observeState()constunsubscribe=outerSubscribe(observeState)return{ unsubscribe }},[$$observable](){returnthis}}}
functionreplaceReducer(nextReducer){if(typeofnextReducer!=='function'){thrownewError('Expected the nextReducer to be a function.')}currentReducer=nextReducer}
functionapplyMiddleware(...middlewares){returncreateStore=>(...args)=>{conststore=createStore(...args)// args 为 (reducer, initialState)letdispatch=()=>{thrownewError('Dispatching while constructing your middleware is not allowed. '+'Other middleware would not be applied to this dispatch.')}constmiddlewareAPI={// 给 middleware 的 storegetState: store.getState,dispatch: (...args)=>dispatch(...args)}constchain=middlewares.map(middleware=>middleware(middlewareAPI))// chain 是一个参数为 next 的匿名函数的数组(中间件执行返回的函数)dispatch=compose(...chain)(store.dispatch)// 经过 compose 函数后返回的结果,是经过 middlewares 包装后的 dispatch return{// 返回 dispatch 增强后的 store
...store,
dispatch
}}}
这是分析 redux 源码系列第一篇。
下面是 Redux 版本4.0.1 源码的解读。
createStore
createStore
方法接受三个参数,第一个参数为reducer
,第二个参数是preloadedState
(可选),第三个是参数是enhancer
。返回一个 对象store
。store
中包含方法dispatch
、getState
、subscribe
、replaceReducer
、[$$observable]
。参数
reducer
有可能是一个reducer
,如果有个多个reducer
,则通过combineReducer
函数执行后返回函数作为reducer
。参数
preloadedState
代表初始状态,很多时候都不传,不传该参数时候且enhancer
是函数情况,createStore
函数内部会把enhancer
,作为第二个参数使用,源码如下:参数
enhancer
是store
增强器,是一个函数,createStore
作为enhancer
函数的参数,这里用到了函数式编程,返回函数又传递reducer
和preloadState
参数,执行最终返回一个增强的store
。enhancer
常有的是applyMiddleware()
返回值,react-devrools()
等工具,源码如下:介绍方法之前,下面是一些变量:
dispatch
dispatch
方法,接受一个参数action
,action
是一个对象,该对象必须包括type
属性,否则会报错。dispatch
函数内部,主要是执行了reducer()
函数,得到最新state
,赋值给currentState
,执行订阅者,dispatch
函数返回一个action
对象。源码如下:getState
获取最新的 state,就是返回 currentState。源码如下:
subscribe
添加事件订阅者,每次触发
dispatch(action)
时候,订阅者都会执行。返回取消订阅方法
unSubscribe
。这里采用了观察者模式/发布-订阅者模式。源码如下:注意:订阅者必须是函数,否则报错。
observable
让一个对象可被观察。被观察对象必须是对象,否则报错。这里作者用到了第三方库
symbol-observable
,对currentState
进行观察。源码如下:ECMAScript Observables
目前只是草案,还没正式使用。replaceReducer
替换
reducer
,一般用不到。源码也简单,把nextReducer
赋值给currentReducer
。源码如下:上面
dispatch
、getState
、subscribe
、replaceReducer
、[$$observable]
这些方法使用了闭包,一直保持对currentState
、currentReducer
、currentListeners
、nextListeners
、isDispatching
等变量的引用。比如,dispatch
改变currentState
,相应的其他方法中,currentState
也会跟着变,所以这些方法之间是存在联系的。applyMiddleware
执行中间件的方法,中间件可以有很多,有自定义的如:打印日志,也有比较知名的 如:
redux-chunk
、redux-promise
、redux-saga
等,后续会分析。applyMiddleware()
通常是上面提到的createStore
方法的第三个参数enhancer
,源码如下:结合上面代码可以等价于
applyMiddleware
使用了函数式编程,接收第一个参数元素为middlewares
的数组,返回值接收createStore
为参数的函数,返回值接收dispatch
函数,接收一个action
如(reducer, state)
,最终返回增强版的store
。源码如下:
compose
源码如下:
虽然源代码没几行,作者实现方式太厉害了,如果理解起来有点费劲,可以看看下面例子分析:
所以作者的用意是
compose(f, g, h)
返回(...args) => f(g(h(...args)))
,其中f、g、h
是一个个中间件middleware
。结合上面
applyMiddleware
源码有一段dispatch = compose(...chain)(store.dispatch)
,所以args
为store.dispatch
,(store.dispatch) => f(g(h(store.dispatch)))
,执行第一个中间件h(store.dispatch)
,返回dispatch
函数(参数为 action 的函数)作为下一个中间件的参数,通过一层层的传递,最终返回一个经过封装的dispatch
函数。下面是打印日志中间件例子:
注意:但如果在某个中间件中使用了
store.dipsatch()
,而不是next()
,那么就会回到起始位置,会造成无限循环了。每次触发一个 dispatch,中间件都会执行,打印的顺序为
dispatch distapch2 finish2 finish
。combineReducer
这个 API 理解为:如果有多个 reducer,那么需要把它们合成一个 reducer,在传给函数
createStore(reducer)
。核心源码如下:
bindActionCreators
这个 API 可以理解为:生成 action 的方法。主要是把 dispatch 也封装进
bindActionCreator(actionCreator, dispatch)
方法里面去,所以调用时候可以直接触发dispatch(action)
,不需要在手动调用 dispatch。源码如下:The text was updated successfully, but these errors were encountered: