Redux概念
Redux的核心本质就是一个发布订阅模式。

Redux的三个基本原则:
- 单一数据源。在Redux中一般只有一个store,用来存放数据。
- 只读的state。更改状态的唯一方法是触发一个动作action,action 描述了这次修改行为的相关信息的对象。由于action只是简单的对象,因此可以将它们记录,序列化,存储并在以后进行调试。
- 使用纯函数进行操作更改state。为了描述 action 如何修改状态,需要使用reducer 函数。reducer 函数接收前一次的 state 和 action,返回新的 state, 而不是改变先前的state。只要传入相同 的state 和 action,无论reducer被调用多少次,那么就一定返回相同的结果。
Redux源码浅析
createStore
function createStore(reducer, preloadedState, enhancer) {
// 删除了一些参数矫正的代码
if (typeof enhancer !== 'undefined') {
if (typeof enhancer !== 'function') {
throw new Error('Expected the enhancer to be a function.')
}
// store enhancer的使用,也就是使用传入的中间件
// enhancer就是后续会提到的applyMiddleware函数
return enhancer(createStore)(reducer, preloadedState)
}
let currentReducer = reducer
let currentState = preloadedState
let currentListeners = []
let nextListeners = currentListeners
let isDispatching = false
// 这个方法用于保持nextListeners和currentListeners的同步
// nextListeners 是从currentListeners浅拷贝来的。
// 订阅的时候是操作nextListeners, 防止在dispatch的时候执行subscribe/unsubscribe带来的bug
// 在dispatch 的时候会同步 currentListeners 和 nextListeners (currentListeners = nextListeners)
function ensureCanMutateNextListeners() {
if (nextListeners === currentListeners) {
nextListeners = currentListeners.slice()
}
}
// 获取当前currentState
function getState() {
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
}
// 订阅一个listener,是操作在nextListeners上的
// 返回的是一个函数,用于删除这个订阅的listener,也是在nextListeners上操作的
// 删除订阅不会在当前的dispatch中生效,而是会在下一次dispatch的时候生效
function subscribe(listener) {
if (typeof listener !== 'function') {
throw new Error('Expected the listener to be a function.')
}
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#subscribelistener for more details.'
)
}
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#subscribelistener for more details.'
)
}
isSubscribed = false
ensureCanMutateNextListeners()
const index = nextListeners.indexOf(listener)
nextListeners.splice(index, 1)
currentListeners = null
}
}
// 触发action
// 1. 执行reducer,更新state
// 2. 执行订阅的listener
// 返回的是传入的action, 用于调试记录
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++) {
const listener = listeners[i]
listener()
}
return action
}
// 替换当前的reducer
function replaceReducer(nextReducer) {
if (typeof nextReducer !== 'function') {
throw new Error('Expected the nextReducer to be a function.')
}
currentReducer = nextReducer
// 触发一个内部的REPLACE action
dispatch({ type: ActionTypes.REPLACE })
}
// 用于 observable/reactive libraries
function observable() {
const outerSubscribe = subscribe
return {
subscribe(observer) {
if (typeof observer !== 'object' || observer === null) {
throw new TypeError('Expected the observer to be an object.')
}
function observeState() {
if (observer.next) {
observer.next(getState())
}
}
observeState()
const unsubscribe = outerSubscribe(observeState)
return { unsubscribe }
},
[$$observable]() {
return this
}
}
}
// 触发一个INIT action,用于创建初始state树
dispatch({ type: ActionTypes.INIT })
return {
dispatch,
subscribe,
getState,
replaceReducer,
[$$observable]: observable
}
}
applyMiddleware 详解
function applyMiddleware(...middlewares) {
// 返回的函数就是在createStore中调用的那个enhancer
return (createStore) => (...args) => {
// 创建store, 可以获取dispatch和getState
const store = createStore(...args)
let dispatch = () => {
throw new Error(
'Dispatching while constructing your middleware is not allowed. ' +
'Other middleware would not be applied to this dispatch.'
)
}
// 封装传入中间件的api
const middlewareAPI = {
getState: store.getState,
dispatch: (...args) => dispatch(...args),
}
// 给中间件们绑定能dispatch和getState的api
const chain = middlewares.map((middleware) => middleware(middlewareAPI))
// 从这里就可以看出middleware就是来加强dispatch的,在dispatch了一个action后搞点事情
// compose的本质就是用于串联执行中间件
// 这个dispatch也重写个middlewareAPI调用的dispatch
dispatch = compose(...chain)(store.dispatch)
return {
...store,
dispatch,
}
}
}
详解 dispatch = compose(...chain)(store.dispatch)
compose的本质,组合多个函数, 用于串联执行中间件
const compose =(...middlewares) => middlewares.reduce((f1, f2) => (...args) => f1(f2(...args)))
先看看标准的middleware
({ dispatch, getState }) => (next) => (action) => {
// 搞点事情
const state = next(action)
// 搞点事情
return state
}
去掉getState和dispatch的实现dispatch = compose(...chain)(store.dispatch)中的chain可以理解为:
const middlewares = [
(next) => (action) => {
console.log('middleware 1')
next(action)
console.log('middleware 1 after')
},
(next) => (action) => {
console.log('middleware 2')
next(action)
console.log('middleware 2 after')
},
(next) => (action) => {
console.log('middleware 3')
next(action)
console.log('middleware 3 after')
},
]
调用上面的chain
const compose = middlewares.reduce((f1, f2) => (...args) => f1(f2(...args)))
// compose好后传入middleware 1 的next就是middleware 2, 传入middleware 2 的next就是middleware3
// 而middleware 3 的next就是调用compose后的传入的原始dispatch
const dispatch = compose((action) => {
console.log('origin dispatch', action)
})
// 最终执行绑定好后的dispatch,就相当于最终执行每个middleware,每个middleware会传递action参数给原始的dispatch
// redux-thunk 的核心原理就是:检测到传入的action如果是函数类型,就执行这个函数
dispatch({ a: 3 })
// log 如下
middleware 1
middleware 2
middleware 3
origin dispatch {a: 3}
middleware 3 after
middleware 2 after
middleware 1 after
applyMiddleware的本质就是把中间件函数参数先一个一个的绑定好,来增强store 的dispatch的执行
combineReducers
combineReducers(reducers) {
const reducerKeys = Object.keys(reducers)
const finalReducers = {}
// 收集所有传入的 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)
// 在 dispatch 时会执行 combination 函数,
// 遍历执行所有 reducer 函数。如果某个 reducer 函数返回了新的 state,就标记hasChanged为true,
// 所有的 reducer 函数都会被执行一遍
// hasChanged ? 返回新的state : 返回原来的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
}
hasChanged =
hasChanged || finalReducerKeys.length !== Object.keys(state).length
return hasChanged ? nextState : state
}
}