前言
Redux 源码的体量算是比较小的了,但是详细解读还是有点压力,在此简单解读下,目的是能大概理解其原理。直接看导出的 API:createStore
、combineReducers
、bindActionCreators
、applyMiddleware
、compose
,其中 bindActionCreators
暂时不想理会,余下的依次介绍。
createStore
关键代码(省去一些加强健壮性的代码)以及对应的解读注释如下:
// 函数接受三个参数,第一个是 reducer,第二个是初始 state,第三个是由 applyMiddleware
// 生成的 enhancer
export default function createStore(reducer, preloadedState, enhancer) {
if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
enhancer = preloadedState
preloadedState = undefined
}
if (typeof enhancer !== 'undefined') {
if (typeof enhancer !== 'function') {
throw new Error('Expected the enhancer to be a function.')
}
return enhancer(createStore)(reducer, preloadedState) // 可以看出 enhancer
// 是一个以 createStore 为参数然后返回一个 createStore 的高阶函数,待会儿通过
// applyMiddleware 可以看到这个 enhancer 到底是怎么起作用的
}
let currentReducer = reducer
let currentState = preloadedState
let currentListeners = []
let nextListeners = currentListeners
let isDispatching = false
function ensureCanMutateNextListeners() {
if (nextListeners === currentListeners) {
nextListeners = currentListeners.slice()
}
}
function getState() { // 返回当前的 state
if (isDispatching) {
throw new Error(
'You may not call store.getState() while the reducer is executing. ' +
'The reducer has already received the state as an argument. ' +
'Pass it down from the top reducer instead of reading it from the store.'
)
}
return currentState
}
function subscribe(listener) { // 订阅函数,每当 dispatch 的时候 listeners 都会执行
if (isDispatching) {
throw new Error(
'You may not call store.subscribe() while the reducer is executing. ' +
'If you would like to be notified after the store has been updated, subscribe from a ' +
'component and invoke store.getState() in the callback to access the latest state. ' +
'See https://redux.js.org/api-reference/store#subscribe(listener) for more details.'
)
}
let isSubscribed = true
ensureCanMutateNextListeners()
nextListeners.push(listener)
// 返回值是一个可以取消当前 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)
}
}
// dispatch,通过这个函数 dispatch action 借由 reducers 来生成一个新的 state
function dispatch(action) {
if (!isPlainObject(action)) {
throw new Error(
'Actions must be plain objects. ' +
'Use custom middleware for async actions.'
)
}
if (typeof action.type === 'undefined') {
throw new Error(
'Actions may not have an undefined "type" property. ' +
'Have you misspelled a constant?'
)
}
if (isDispatching) {
throw new Error('Reducers may not dispatch actions.')
}
try {
isDispatching = true
currentState = currentReducer(currentState, action)
} finally {
isDispatching = false
}
const listeners = (currentListeners = nextListeners)
for (let i = 0; i < listeners.length; i++) { // 如前所述,每 dispatch 一个 action 时
// 都会去执行所有的 listeners
const listener = listeners[i]
listener()
}
return action // 返回值和传入的参数一样,action
}
function replaceReducer(nextReducer) { // 替换 reducer
if (typeof nextReducer !== 'function') {
throw new Error('Expected the nextReducer to be a function.')
}
currentReducer = nextReducer
// replace reducer 后 dispatch 一个 REPLACE action
dispatch({ type: ActionTypes.REPLACE })
}
// When a store is created, an "INIT" action is dispatched so that every
// reducer returns their initial state. This effectively populates
// the initial state tree.
// store 生成后 dispatch 一个 INIT 的 action
dispatch({ type: ActionTypes.INIT })
return {
dispatch,
subscribe,
getState,
replaceReducer
}
}
createStore
主要的作用就是根据提供的 reducer
、initialState
和 enhancer
生成 store
,然后 store 可以提供 dispatch
、subscribe
、getState
、replaceReducer
等方法。
combineReducers
combineReducer
的作用是将多个(如果有的话) reducer
整合成一个总的 reducer
,关键代码:
// reducers 是一个 plain object,一个 key 对应一个 reducer
export default function combineReducers(reducers) {
const reducerKeys = Object.keys(reducers)
const finalReducers = {}
for (let i = 0; i < reducerKeys.length; i++) {
const key = reducerKeys[i]
// 过滤无效的 reducer
if (typeof reducers[key] === 'function') {
finalReducers[key] = reducers[key]
}
}
const finalReducerKeys = Object.keys(finalReducers)
// 返回值依然是一个以 state 和 action 为参数的 reducer,但是它可以处理所有的 type 的 action
return function combination(state = {}, action) {
let hasChanged = false
const nextState = {}
// 具体处理 action 的做法是,把每个 action 代入所有 reducer 生成对应的结果,然后再整合
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)
nextState[key] = nextStateForKey
hasChanged = hasChanged || nextStateForKey !== previousStateForKey
}
return hasChanged ? nextState : state
}
}
compose
这个方法的代码最少:
export default function compose(...funcs) {
if (funcs.length === 0) {
return arg => arg
}
if (funcs.length === 1) {
return funcs[0]
}
return funcs.reduce((a, b) => (...args) => a(b(...args)))
}
funcs
是一个函数数组,reduce
是数组的归并方法。这个方法接受一系列的函数作为参数,而且这一系列函数,从右到左,上一个函数的返回值可以为下一个函数的参数,最终返回一个以最右边的函数的参数为参数(这个参数再依次交给左边的函数处理,返回后继续此步骤,一直到最左边)以最左边的函数的返回值为返回值的复合函数。比如:
const F = compose(f1, f2. f3, f4, ..., fn)
F //f1(f2...(fn(...args)))
applyMiddleware
applyMiddleware
,可以说这个方法为 Redux 提供了各种可能性,关键代码:
import compose from './compose'
export default function applyMiddleware(...middlewares) {
// 返回值是一个同时以 createStore 为参数和返回值的闭包
return createStore => (...args) => {
const store = createStore(...args) // 这里的store与没有enhancer时的并无二致
let dispatch = () => {
throw new Error( // 中间件中不允许 dispatch
`Dispatching while constructing your middleware is not allowed. ` +
`Other middleware would not be applied to this dispatch.`
)
}
// 中间件API,规定了 middleware 是一个以 { getState, dispatch } 为参数的函数
const middlewareAPI = {
getState: store.getState,
dispatch: (...args) => dispatch(...args)
}
// chain 的每个元素依然是一个函数,经过 compose 作用后返回一个合成函数,合成函数以
// store.dispatch 为参数,最终生成一个加强了的 dispatch
const chain = middlewares.map(middleware => middleware(middlewareAPI))
dispatch = compose(...chain)(store.dispatch)
// 上面语句分开写就是 const composedFn = compose(...chain)
// dispatch = composedFn(store.dispatch)
// 其中 composedFn: (...args) => chain[0](chain[1](...(chain[length - 1](...args))))
// 可以看到,`createStore` 经过 `storeEnhancer` 加强之后,其实只是用新的`dispatch` 将原来
// 的 `dispatch` 替换,其他的部分保持不变
return {
...store,
dispatch
}
}
}
这个方法接受一系列的 Redux 的 middleware
为参数,然后返回一个以 createStore
为参数的 storeEnhancer
,其实 storeEnhancer
enhance 的是 dispatch
(这里好像并不准确,因为除了由中间件生成的 storeEnhancer 以外,还有其他的 storeEnhancer,而这些 storeEnhancer 就有更强的功能,比如像 devToolsExtension
这样的扩展工具)。由于每个 middleware 在作用 { getState, dispatch }
后可以被 compose
处理,那我们可以知道 middleware({ getState, dispatch })
的返回值是一个函数,而且这个函数的参数和返回值是具有相同签名的函数,于是 middleware 的函数签名大概是:({ getState, dispatch }) => next => action
,其中 next(action)
表示将 action
交由下一个 middleware 处理,最后一个 middleware 的 next
即 dispatch
。
举个例子:
//m1, m2, m3 是三个中间件
const middlewares = [m1, m2, m3]
const storeEnhancer = applyMiddleWare(...middlewares)
const store = createStore(reducer, {}, storeEnhancer)
export default store
store.dispatch
被强化的过程是这样:
普通 dispatch
-> 被 m3
强化后的 dispatch
(记为 m3(dispatch)
) -> 再被 m2
强化后的 dispatch
(记为 m2(m3(dispatch))
) -> 再被 m1
强化后的 dispatch
(记为 m1(m2(m3(dispatch)))
。
对应地,加载了上述中间件的 store
dispatch
一个 action
的过程是这样:
m1(m2(m3(dispatch)))(action)
-> next(action)
(next === m2(m3(dispatch))
)-> next(action)
(next === m3(dispacth)
)-> next(action)
(next === dispatch
)。