Redux主要做的几件事情
- 生成一个全局唯一的state
- 仅提供一种方法去修改state
- 使用中间件加强dispatch函数
- 提供listener在数据变化的时候执行相应的操作
使用闭包在createStore函数保存唯一的state
createStore.js
输出:
{
dispatch,
subscribe,
getState,
replaceReducer,
[$$observable]: observable
}
这些函数会调用到闭包里面的一些变量,如currentState, currentReducer, currentListeners。
仅提供dispatch去修改state
dispatch
作用:将action和state传入reducer并修改对应的state,并执行listeners数组里面的所有listener 核心就是这句
currentState = currentReducer(currentState, action)
combineReducers.js
作用:将一堆reducer存在闭包里面,最终返回一个总的reducer
输入:一个对象,对象中每个属性对应一个reducer
{
task: (state, action) => {
switch (action.type) {
case 'CHANGE_FILTER_STATUS':
state.filterStatus = action.data
return state
default:
return state;
}
}
}
核心代码:
// 将reducer存到闭包中
const finalReducers = {}
for (let i = 0; i < reducerKeys.length; i++) {
const key = reducerKeys[i]
if (process.env.NODE_ENV !== 'production') {
if (typeof reducers[key] === 'undefined') {
warning(`No reducer provided for key "${key}"`)
}
}
if (typeof reducers[key] === 'function') {
finalReducers[key] = reducers[key]
}
}
// 输出:一个总的recuder函数,作用为遍历所有的reducer,返回一个state
return function combination(state = {}, action) {
let hasChanged = false
const nextState = {}
for (let i = 0; i < finalReducerKeys.length; i++) {
const key = finalReducerKeys[i]
const reducer = finalReducers[key]
const previousStateForKey = state[key]
const nextStateForKey = reducer(previousStateForKey, action)
if (typeof nextStateForKey === 'undefined') {
const errorMessage = getUndefinedStateErrorMessage(key, action)
throw new Error(errorMessage)
}
nextState[key] = nextStateForKey
hasChanged = hasChanged || nextStateForKey !== previousStateForKey
}
return hasChanged ? nextState : state
}
通过applyMiddleware加强dispatch函数
核心代码:
const middlewareAPI = {
getState: store.getState,
dispatch: (...args) => dispatch(...args)
}
const chain = middlewares.map(middleware => middleware(middlewareAPI))
dispatch = compose(...chain)(store.dispatch)
其中compose其实就是使用array.reduce从右到左执行函数
compose核心代码:
return funcs.reduce((a, b) => (...args) => a(b(...args)))
通过subscribe注册listener
每次添加listener时都先深复制复制一份之前的listener
返回一个unsubscribe函数
let isSubscribed = true
ensureCanMutateNextListeners()
nextListeners.push(listener)
return function unsubscribe() {
if (!isSubscribed) {
return
}
if (isDispatching) {
throw new Error(
'You may not unsubscribe from a store listener while the reducer is executing. ' +
'See https://redux.js.org/api-reference/store#subscribe(listener) for more details.'
)
}
isSubscribed = false
ensureCanMutateNextListeners()
const index = nextListeners.indexOf(listener)
nextListeners.splice(index, 1)
}
用array.slice()方法来深复制
function ensureCanMutateNextListeners() {
if (nextListeners === currentListeners) {
nextListeners = currentListeners.slice()
}
}
总结
通过分析redux的源码,首先我们可以更好的理解我们使用redux的时候,里面具体发生了什么事情,其次是可以更清楚地看到各种redux的插件是如何加入到redux里面的,对于我们以后使用redux或者redux的插件会有帮助。
另一方面,从代码的组织上来看,可以看到了里面有很多闭包的使用,还有各种各样的错误处理,以及简洁的语法,对于自身代码质量的提高也有一定的影响。