硬菜源码解析(部分关键源码):
createStore
export default function createStore(reducer, initialState) {
// 这些都是闭包变量
var currentReducer = reducer
var currentState = initialState
var listeners = []
var isDispatching = false;
// 返回当前的state,核心方法之一
function getState() {
return currentState
}
// 注册listener,同时返回一个取消事件注册的方法,核心方法之二
function subscribe(listener) {
listeners.push(listener)
var isSubscribed = true
return function unsubscribe() {
//解绑是将 listeners 都移除掉,在后续 dispatch 中不存在 listeners
if (!isSubscribed) {
return
}
isSubscribed = false
var index = listeners.indexOf(listener)
listeners.splice(index, 1)
}
}
// 通过action该改变state,然后执行subscribe注册的方法,核心方法之三
function dispatch(action) {
try {
isDispatching = true
currentState = currentReducer(currentState, action)
} finally {
isDispatching = false
}
//在发出 action 后触发 subscribe 的 listeners,执行该方法
listeners.slice().forEach(listener => listener())
return action
}
// 替换reducer,修改state变化的逻辑,核心方法之四
function replaceReducer(nextReducer) {
currentReducer = nextReducer
dispatch({ type: ActionTypes.INIT })
}
// 创建store时,执行内部一个dispatch,得到初始state
dispatch({ type: ActionTypes.INIT })
}
主要理解 getState,dispatch,subscribe 和 unsubscribe,replaceReducer 方法。
之前都只讲了单一 reducer 完成单一页面或者应用,但当应用变得复杂,如果还是用一个 reducer 去处理的话,那么必然会产生 switch N 多 N 多的case
那样既不美观也不利于性能。
所以将这些 N 多的 case 拆分到多个 reducer 去处理,每个 reducer 只管理应用中整个 state 中的部分属性,然后再用 combineReducer 最终再合成为一个 Reducer 入口,同时也就改变了 state 的结构,只有一个 state 包含了整个应用每个部分的状态。
state:{
partA:{},
partB:{},
....
}
combineReducer 用法:
var rootReducer = combineReducers({
count: count,
year: year,
});
看一下 combineReducer 关键源码(完整版自己搜索一下),理解是如何工作的:
export default function combineReducers(reducers) { //参数为一个普通Object
var reducerKeys = Object.keys(reducers) //获取所有 Object 的 key 值数组
var finalReducers = {}//过滤后的可用 reducer
for (var i = 0; i < reducerKeys.length; i++) {
//遍历排除不合法的reducer
......
}
//返回一个总的reducer闭包,它的初步调用是在creatStore中初始化状态时;
return function combination(state = {}, action) {
......
var nextState={};
var hasChanged = false;
//遍历所有可用 reducer对象,然后执行reducer获取初始化状态,finalReducerKeys 为可用 reducer 的 key 值数组
for (var i = 0; i < finalReducerKeys.length; i++) {
var key = finalReducerKeys[i] //取一个 reducer 的 key
var reducer = finalReducers[key] //通过 key 值找到对应的 reducer
var previousStateForKey = state[key] //当前 reducer 的 state,作为这次reducer 的 initialState
var nextStateForKey = reducer(previousStateForKey, action) //获取初始化状态
if (typeof nextStateForKey === 'undefined') {
//reducer 返回 undefined,则报错
var errorMessage = getUndefinedStateErrorMessage(key, action)
throw new Error(errorMessage) }
nextState[key] = nextStateForKey//问题一
hasChanged = hasChanged || nextStateForKey !== previousStateForKey }
// 判断初始化状态是否改变,返回对象的状态
return hasChanged ? nextState : state
}}
首先明确一点,经过 combineReducer 捆绑后返回的是一个和 reducer 形式一直的函数 combination(state,action),其实也就是一个 reducer!
问题一:这里的 nextStateForKey 和 nextState[key]一定会变吗?答案是不一定,其实每次调用 dispatch 的时候会把 action 发送到 rootReducer 中,然后遍历所有 reducer,返回其更新后的 state,
那么就可能是这个 action 的 type 不一定在这个 reducer 中找到对应的 case 进行修改,所以不一定会变,只有找到了对应的 type 才会执行相应的逻辑修改 state。
这里最重要的是,每一个 reducer 有专属自己的唯一 key 值,之后的所有操作都和 key 值"绑定"
以 key='count'为例,即reducer['count']返回的值赋到state[key]。
未完待续。。