createStore
function createStore(reducer, preloadedState, enhancer) { if(enhancer是有效的){ // 这个我们后面会解释,可以先忽略 return enhancer(createStore)(reducer, preloadedState) } let currentReducer = reducer // 当前store中的reducer let currentState = preloadedState // 当前store中存储的状态 let currentListeners = [] // 当前store中放置的监听函数 let nextListeners = currentListeners // 下一次dispatch时的监听函数 // 注意:当我们新添加一个监听函数时,只会在下一次dispatch的时候生效。 //... // 获取state function getState() { //... } // 添加一个监听函数,每当dispatch被调用的时候都会执行这个监听函数 function subscribe() { //... } // 触发了一个action,因此我们调用reducer,得到的新的state,并且执行所有添加到store中的监听函数。 function dispatch() { //... } //... //dispatch一个用于初始化的action,相当于调用一次reducer //然后将reducer中的子reducer的初始值也获取到 //详见下面reducer的实现。 return { dispatch, subscribe, getState, //下面两个是主要面向库开发者的方法,暂时先忽略 //replaceReducer, //observable }}function getState() { return currentState}function subscribe(listener) { // 添加到监听函数数组, // 注意:我们添加到了下一次dispatch时才会生效的数组 nextListeners.push(listener) let isSubscribe = true //设置一个标志,标志该监听器已经订阅了 // 返回取消订阅的函数,即从数组中删除该监听函数 return function unsubscribe() { if(!isSubscribe) { return // 如果已经取消订阅过了,直接返回 } isSubscribe = false // 从下一轮的监听函数数组(用于下一次dispatch)中删除这个监听器。 const index = nextListeners.indexOf(listener) nextListeners.splice(index, 1) }}function dispatch(action) { //调用reducer,得到新state currentState = currentReducer(currentState, action); //更新监听数组 currentListener = nextListener; //调用监听数组中的所有监听函数 for(let i = 0; i < currentListener.length; i++) { const listener = currentListener[i]; listener(); }}
bindActionCreators
combineReducers
function combineReducers(reducers) { //先获取传入reducers对象的所有key const reducerKeys = Object.keys(reducers) const finalReducers = {} // 最后真正有效的reducer存在这里 //下面从reducers中筛选出有效的reducer for(let i = 0; i < reducerKeys.length; i++){ const key = reducerKeys[i] if(typeof reducers[key] === 'function') { finalReducers[key] = reducers[key] } } const finalReducerKeys = Object.keys(finalReducers); //这里assertReducerShape函数做的事情是: // 检查finalReducer中的reducer接受一个初始action或一个未知的action时,是否依旧能够返回有效的值。 let shapeAssertionError try { assertReducerShape(finalReducers) } catch (e) { shapeAssertionError = e } //返回合并后的reducer return function combination(state= {}, action){ //这里的逻辑是: //取得每个子reducer对应的state,与action一起作为参数给每个子reducer执行。 let hasChanged = false //标志state是否有变化 let nextState = {} for(let i = 0; i < finalReducerKeys.length; i++) { //得到本次循环的子reducer const key = finalReducerKeys[i] const reducer = finalReducers[key] //得到该子reducer对应的旧状态 const previousStateForKey = state[key] //调用子reducer得到新状态 const nextStateForKey = reducer(previousStateForKey, action) //存到nextState中(总的状态) nextState[key] = nextStateForKey //到这里时有一个问题: //就是如果子reducer不能处理该action,那么会返回previousStateForKey //也就是旧状态,当所有状态都没改变时,我们直接返回之前的state就可以了。 hasChanged = hasChanged || previousStateForKey !== nextStateForKey } return hasChanged ? nextState : state }}
applyMiddleWare
function applyMiddleware(...middlewares) { // 返回一个函数A,函数A的参数是一个createStore函数。 // 函数A的返回值是函数B,其实也就是一个加强后的createStore函数,大括号内的是函数B的函数体 return createStore => (...args) => { //用参数传进来的createStore创建一个store const store = createStore(...args) //注意,我们在这里需要改造的只是store的dispatch方法 let dispatch = () => { //一个临时的dispatch //作用是在dispatch改造完成前调用dispatch只会打印错误信息 throw new Error(`一些错误信息`) } //接下来我们准备将每个中间件与我们的state关联起来(通过传入getState方法),得到改造函数。 const middlewareAPI = { getState: store.getState, dispatch: (...args) => dispatch(...args) } //middlewares是一个中间件函数数组,中间件函数的返回值是一个改造dispatch的函数 //调用数组中的每个中间件函数,得到所有的改造函数 const chain = middlewares.map(middleware => middleware(middlewareAPI)) //将这些改造函数compose(翻译:构成,整理成)成一个函数 //用compose后的函数去改造store的dispatch dispatch = compose(...chain)(store.dispatch) // compose方法的作用是,例如这样调用: // compose(func1,func2,func3) // 返回一个函数: (...args) => func1( func2( func3(...args) ) ) // 即传入的dispatch被func3改造后得到一个新的dispatch,新的dispatch继续被func2改造... // 返回store,用改造后的dispatch方法替换store中的dispatch return { ...store, dispatch } }}function compose(...funcs) { // 当未传入函数时,返回一个函数:arg => arg if(funcs.length === 0) { return arg => arg } // 当只传入一个函数时,直接返回这个函数 if(funcs.length === 1) { return funcs[0] } // 返回组合后的函数 return funcs.reduce((a, b) => (...args) => a(b(...args))) //reduce是js的Array对象的内置方法 //array.reduce(callback)的作用是:给array中每一个元素应用callback函数 //callback函数: /* *@参数{accumulator}:callback上一次调用的返回值 *@参数{value}:当前数组元素 *@参数{index}:可选,当前元素的索引 *@参数{array}:可选,当前数组 * *callback( accumulator, value, [index], [array]) */}