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
/** * Composes single-argument functions from right to left. The rightmost * function can take multiple arguments as it provides the signature for * the resulting composite function. * * @param {...Function} funcs The functions to compose. * @returns {Function} A function obtained by composing the argument functions * from right to left. For example, compose(f, g, h) is identical to doing * (...args) => f(g(h(...args))). */exportdefaultfunctioncompose(...funcs){if(funcs.length===0){returnarg=>arg;}if(funcs.length===1){returnfuncs[0];}returnfuncs.reduce((a,b)=>(...args)=>a(b(...args)))}
Turns an object whose values are action creators, into an object with the same keys, but with every action creator wrapped into a dispatch call so they may be invoked directly.
exportdefaultfunctionbindActionCreators(actionCreators,dispatch){// 先判断是不是能返回想要的对象的函数,是就直接返回if(typeofactionCreators==='function'){returnbindActionCreator(actionCreators,dispatch)}// 如果不是对象,直接抛出错误if(typeofactionCreators!=='object'||actionCreators===null){thrownewError(`bindActionCreators expected an object or a function, instead received ${actionCreators===null ? 'null' : typeofactionCreators}. `+`Did you write "import ActionCreators from" instead of "import * as ActionCreators from"?`)}// 这段代码的作用是,遍历actionCreators,对其中的值全部调用bindActionCreator方法// 再由bindActionCreator对返回的纯对象进行dispatchconstkeys=Object.keys(actionCreators)constboundActionCreators={}for(leti=0;i<keys.length;i++){constkey=keys[i]constactionCreator=actionCreators[key]if(typeofactionCreator==='function'){boundActionCreators[key]=bindActionCreator(actionCreator,dispatch)}}returnboundActionCreators}
总结来说就是接收一个对象reducers,将参数过滤后返回一个函数。该函数里有一个过滤参数后的对象 finalReducers,遍历该对象,然后执行对象中的每一个 reducer 函数,最后将新的 state 返回。
再看一个使用到的辅助函数assertReducerShape
functionassertReducerShape(reducers){Object.keys(reducers).forEach(key=>{constreducer=reducers[key]// 接下来要判断action为{ type: ActionTypes.INIT }时是否有初始值constinitialState=reducer(undefined,{type: ActionTypes.INIT})if(typeofinitialState==='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.`)}// 对reduer执行一次随机的action,如果没有返回,则抛出错误,// 告知你不要处理redux中的私有的action,对于未知的action应当返回当前的state// The initial state may not be undefined, but can be null 初始值可以为null,但不能为underfinedconsttype='@@redux/PROBE_UNKNOWN_ACTION_'+Math.random().toString(36).substring(7).split('').join('.')if(typeofreducer(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.`)}})}
exportdefaultfunctioncreateStore(reducer,preloadedState,enhancer){// 如果没有传入参数enhancer,并且preloadedState的值又是一个函数的话// createStore会认为你省略了preloadedState,因此第二个参数就是enhancerif(typeofpreloadedState==='function'&&typeofenhancer==='undefined'){enhancer=preloadedStatepreloadedState=undefined}if(typeofenhancer!=='undefined'){// 传入了enhancer但是却又不是函数类型。会抛出错误if(typeofenhancer!=='function'){thrownewError('Expected the enhancer to be a function.')}// 一切都符合预期的话,那就先执行enhancer,再执行createStorereturnenhancer(createStore)(reducer,preloadedState)}// 如果传入的reducer也不是函数,抛出相关错误if(typeofreducer!=='function'){thrownewError('Expected the reducer to be a function.')}// 当前reducerletcurrentReducer=reducer// 当前state// 在同构应用中,你可以决定是否把服务端传来的 state 水合(hydrate)后传给它,或者从之前保存的用户会话中恢复一个传给它letcurrentState=preloadedState// 当前监听函数数组letcurrentListeners=[]// 这里按照某大神的说法// 这是一个很重要的设计,为的就是每次在遍历监听器的时候保证 currentListeners 数组不变// 可以考虑下只存在 currentListeners 的情况,如果我在某个 subscribe 中再次执行 subscribe// 或者 unsubscribe,这样会导致当前的 currentListeners 数组大小发生改变,从而可能导致// 索引出错letnextListeners=currentListenersletisDispatching=falsefunctionensureCanMutateNextListeners(){// 如果 currentListeners 和 nextListeners 相同,就赋值回去if(nextListeners===currentListeners){nextListeners=currentListeners.slice()}}...其他代码省略了// 返回的就是一整个store,store里面包含了下面几个方法return{
dispatch,
subscribe,
getState,
replaceReducer,[$$observable]: observable}}
接下来再看看它里面封装的几个方法
1、dispatch
functiondispatch(action){// 首先检查传入的action是不是纯对象,如果不是则抛出异常if(!isPlainObject(action)){thrownewError('Actions must be plain objects. '+'Use custom middleware for async actions.')}// action中是否存在type,不存在也抛出异常if(typeofaction.type==='undefined'){thrownewError('Actions may not have an undefined "type" property. '+'Have you misspelled a constant?')}// 这里主要是防止循环调用// 如果在reduder中做了dispatch,而dispatch又必然会导致reducer的调用,就会造成死循环if(isDispatching){thrownewError('Reducers may not dispatch actions.')}// 将isDispatching置为true,调用当前的reducer函数,并且返回新的state存入currentState,并将isDispatching置回去try{isDispatching=truecurrentState=currentReducer(currentState,action)}finally{isDispatching=false}// 依次调用监听者,但并不需要把新的state传给监听者,因为这里还有一个store.getState()方法可以获取最新的storeconstlisteners=currentListeners=nextListenersfor(leti=0;i<listeners.length;i++){constlistener=listeners[i]listener()}returnaction}
2、subscribe
subscribe用来订阅store的变化
functionsubscribe(listener){// 首先判断传入的listener是否是函数if(typeoflistener!=='function'){thrownewError('Expected listener to be a function.')}letisSubscribed=true// 该函数在下面// 用来判断nextListeners和currentListeners是否是完全相同// 如果相同(===),将nextListeners赋值为currentListeners的拷贝(值相同,但不是同一个数组)// 然后将当前的监听函数传入nextListenersensureCanMutateNextListeners()nextListeners.push(listener)// isSubscribed是以闭包的形式判断当前监听者函数是否在监听,从而保证只有第一次调用unsubscribe才是有效的returnfunctionunsubscribe(){if(!isSubscribed){return}isSubscribed=falseensureCanMutateNextListeners()constindex=nextListeners.indexOf(listener)nextListeners.splice(index,1)}}
functionreplaceReducer(nextReducer){if(typeofnextReducer!=='function'){thrownewError('Expected the nextReducer to be a function.')}currentReducer=nextReducerdispatch({type: ActionTypes.INIT})}
一、compose
这是一个高阶函数,返回函数的函数被称为高阶函数
它的作用是通过传入函数引用的方式,从右到左依次调用函数,并把上一个函数的值作为下一个函数的参数
文档里面的注释写的很清楚
再看被编译成ES5的写法,其中
b.apply(underfined, arguments)
是因为b()这里代表的是全局,所以要绑定underfined
二、bindActionCreators
主要实现的就是将
ActionCreator
与dispatch
进行绑定,官方的注释里面这么写的翻译过来就是
bindActionCreators
将值为actionCreator
的对象转化成具有相同键值的对象,但是每一个actionCreator
都会被dispatch所包裹调用,因此可以直接使用先看
bindActionCreator
,看清楚了,没有s的返回一个新的函数,该函数调用时会将
actionCreator
返回的纯对象进行dispatch
接下来看
bindActionCreators
代码的作用是对对象actionCreators中的所有值调用
bindActionCreator
,然后返回新的对象三、combineReducers
官方文档
combineReducers
函数总的来说是比较简单的,将大的reducer
函数拆分成一个个小的reducer
分别处理,先看代码
使用变量
nextState
记录本次执行reducer
返回的state
。hasChanged
用来记录前后state
是否发生改变。循环遍历
reducers
,将对应的store
的部分交给相关的reducer
处理,当然对应各个reducer
返回的新的state
仍然不可以是undefined
。最后根据
hasChanged
是否改变来决定返回nextState
还是state
,这样就保证了在不变的情况下仍然返回的是同一个对象。总结来说就是接收一个对象
reducers
,将参数过滤后返回一个函数。该函数里有一个过滤参数后的对象finalReducers
,遍历该对象,然后执行对象中的每一个reducer
函数,最后将新的state
返回。再看一个使用到的辅助函数
assertReducerShape
1、判断
reducers
中的每一个reducer
在action
为{ type: ActionTypes.INIT }
时是否有初始值,如果没有则会抛出异常。2、对
reduer
执行一次随机的action
,如果没有返回,则抛出错误,告知你不要处理redux中的私有的action,对于未知的action应当返回当前的state。并且初始值不能为undefined
,但是可以是null
四、createStore
官方文档
有三个参数,reducer是处理后的reducer纯函数,
preloadedState
是初始状态,而enhancer
使用相对较少,enhancer
是一个高阶函数,用来对原始的createStore
的功能进行增强。先看它的核心代码
接下来再看看它里面封装的几个方法
1、dispatch
2、subscribe
subscribe
用来订阅store
的变化3、getState
这个……emm👶
4、replaceReducer
热更新reducer用的,用的比较少
五、applyMiddleware
看它的代码之前,先加一点预备知识:柯里化函数,通常也称部分求值
举个例子
还不知道的同学可以先去稍微补一下,大概知道柯里化函数干嘛的就行了
由于采用了ES6的结构赋值和箭头函数,
applyMiddleware
代码很短The text was updated successfully, but these errors were encountered: