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
{{ message }}
This repository has been archived by the owner on Nov 30, 2024. It is now read-only.
if((typeofpreloadedState==='function'&&typeofenhancer==='function')||(typeofenhancer==='function'&&typeofarguments[3]==='function')){thrownewError('It looks like you are passing several store enhancers to '+'createStore(). This is not supported. Instead, compose them '+'together to a single function.')}if(typeofpreloadedState==='function'&&typeofenhancer==='undefined'){enhancer=preloadedStatepreloadedState=undefined}if(typeofenhancer!=='undefined'){if(typeofenhancer!=='function'){thrownewError('Expected the enhancer to be a function.')}returnenhancer(createStore)(reducer,preloadedState)}
if(typeofreducer!=='function'){thrownewError('Expected the reducer to be a function.')}letcurrentReducer=reducer// 当前的 reducerletcurrentState=preloadedState// 当前的state,默认为 preloaderState,一般为 undefinedletcurrentListeners=[]// 监听变化的函数队列letnextListeners=currentListeners// 变化之后,下一次的监听变化的函数队列letisDispatching=false// 是否处于 Dispatching 状态
functiondispatch(action){if(!isPlainObject(action)){thrownewError('Actions must be plain objects. '+'Use custom middleware for async actions.')}if(typeofaction.type==='undefined'){thrownewError('Actions may not have an undefined "type" property. '+'Have you misspelled a constant?')}if(isDispatching){thrownewError('Reducers may not dispatch actions.')}try{isDispatching=truecurrentState=currentReducer(currentState,action)}finally{isDispatching=false}constlisteners=(currentListeners=nextListeners)for(leti=0;i<listeners.length;i++){constlistener=listeners[i]listener()}returnaction}
functionensureCanMutateNextListeners(){if(nextListeners===currentListeners){nextListeners=currentListeners.slice()}}functionsubscribe(listener){if(typeoflistener!=='function'){thrownewError('Expected the listener to be a function.')}
...
letisSubscribed=trueensureCanMutateNextListeners()nextListeners.push(listener)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#subscribelistener for more details.')}isSubscribed=falseensureCanMutateNextListeners()constindex=nextListeners.indexOf(listener)nextListeners.splice(index,1)currentListeners=null}}
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.')}returncurrentState}
functionreplaceReducer(nextReducer){if(typeofnextReducer!=='function'){thrownewError('Expected the nextReducer to be a function.')}currentReducer=nextReducer// This action has a similiar effect to ActionTypes.INIT.// Any reducers that existed in both the new and old rootReducer// will receive the previous state. This effectively populates// the new state tree with any relevant data from the old one.dispatch({type: ActionTypes.REPLACE})}
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())}}observeState()constunsubscribe=outerSubscribe(observeState)return{ unsubscribe }},[$$observable](){returnthis}}}
最近在知乎上看到了一篇整理讨论
Vuex、Flux、Redux、Redux-saga、Dva、MobX
这些状态管理库的设计思想的文章,链接在此。想到以前最开始学习
React
的时候,被React
全家桶折磨的那么痛苦,虽然当时也看过别人分享过Redux
的分享,也稍微看了一些源码,目前已经忘记了差不多了。虽然网上已经有太多的分享和整理,但是主要是想写给自己看,温故而知新~Redux 的基本用法
抛开
react
,Redux
非常简单,以官方github
上的示例为样板,稍微改变点东西,以方便我在本地进行调试,我直接把静态资源的redux.js
下载到本地,然后进行代码调试。下面是最简单的使用示例:这个代码就是创建了一个
reducer
然后,使用createStore
创建了一个store
,然后监听了变化,只要变化就打印当前的state
,最后在setTimeout
中进行dispatch
让state
发生变化。可以看到这里暂时还没有使用
applyMiddleware
函数,也就是没有使用中间件,这个放在后面说。入口函数
先看看源码结构:
Redux
这个变量上, 挂载了一些属性,可以从示例代码上看到,入口函数就是createStore
了。首先看一下index.js
入口文件。基本没有什么东西,引入了其他文件的导出,然后汇集一起导出了。
createStore
可以看到
createStore
函数,接受三个参数,第一个就是传入的reducer
处理函数,第二个是预置的state
,第三个用来对createStore
函数进行增强的中间件等工具方法了。一般enhancer
我们都是传入的是applyMiddleware
函数的返回值。函数一进来就会判断第二参数和第三个参数的正确行,这里可以看到,如果第二参数传入的是函数,并且第三个参数没传,这里会把它当成
enhancer
。这就是我们常这样使用的方式:createStore(reducer, applyMiddleware(...))
,只传入两个参数。再之后就是返回enhancer(createStore)(reducer, preloadedState)
的结果,这个放在后面说。紧接着就是判断了
reducer
是否为函数,然后声明了几个变量,用来初始化。中间代码会声明一些操作函数,包括我们常用的
dispatch
,这些函数基本上就是对上面声明的这些变量在进行操作。我们直接看最后面。首先在返回之前,调用了
dispatch
函数,对state
进行了初始化,传入了一个对象,包含对type
的声明,也就是一个action
。dispatch 函数
整个
createStore
直接执行的代码没几行,重要的动作在dispatch({ type: ActionTypes.INIT })
这句上,看看dispatch
的实现。action
必须要是一个字面量对象。action
是否存在type
属性。dispatch
正在执行。isDispatching
设置为true
,然后将当前的state
和传入的action
传入到reducer
去执行,然后得到结果赋值给currentState
。state
已经修改完了,所以将isDispatching
置为false
。currentListeners
赋值为nextListeners
,然后进行遍历,执行里面所有的监听回调函数,最后返回action
。逻辑比较简单,当我们调用
dispatch({ type: ActionTypes.INIT })
的时候,最终是将currentState
和{ type: ActionTypes.INIT }
传入到了我们实现的reducer
函数里面。这时候,
currentState
为undefined
,type
为ActionTypes.INIT
,根据代码,可以看到最终返回的是initialState
。这就是初始的state
的赋值场景了。在我们的应用代码里面会去调用
dispatch
函数,其实每次都是直接调用了reducer
然后去遍历执行了listeners
队列。简单吧,很简单。根据源码反映,只要dispatch
函数的执行,listeners
就会被执行,并不是state
变了才回去执行,由此可以看出redux
的监听就是全量的调用,粒度好像有点大哦。subscribe 函数
对状态进行监听(其实是对执行dispatch监听),是调用的
subscribe
函数,它还会返回一个值用来取消当前函数的监听。isSubscribed
标志,置为true
。ensureCanMutateNextListeners
函数对currentListeners
进行浅拷贝,赋值给nextListeners
。listener
入nextListeners
队列。unsubscribe
函数,这个函数左右就是在nextListeners
队列中找到listener
然后进行删除。getState 函数
直接将
currentState
变量的值进行了返回。replaceReducer 函数
传入一个新的
reducer
函数,进行替换,最后调用一下dispatch
函数,得到reducer
对应的state
。observable 函数
这个函数,我没有使用过,暂时没有碰到相关的场景,根据源码,我理解为,类似于
subscribe
,但是这个监听回调可以结合符合约定的第三方observable
库。比如源码注释提到的https://github.com/tc39/proposal-observable
。小结
以上梳理了没有使用中间件增强的基本流程,让我最深刻的就只有
listener
的调用,只是和dispatch
调用有关,至于state
有没有修改只是简单赋值而已。redux
应用了很多函数式的编程技巧,就比如subscribe
函数最后直接返回取消订阅的函数。The text was updated successfully, but these errors were encountered: