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])
*/
}