Redux,非常出名的状态管理库,它并不是只能用在 React,而使用 React 的会用到 React-Redux
,虽然已经有很多原理、源码的分析文章。但我带着从它源码出发并且添加注释,来去理解和掌握它的思想。
首先需要明白 Redux 和 React Redux 的区别, Redux 是一个状态管理容器,它不属于任何一个框架,而 React Redux 是在 Redux 的基础上结合了 React。
Redux
Redux Analyze,完整的代码注释和 Example 可以看代码,文章中的浅析只保留关键逻辑方便理解,会将大部份非重要判断去除。如
- isDispatching,是否在 dispatch 中或者在 createStore 中
- isPlainObject,是否纯对象
- function,传入的 reducer 是否 function
- isSubscribed,是否已经订阅
createStore
export default function createStore(reducer, preloadedState, enhancer) {
if (typeof enhancer !== 'undefined') {
if (typeof enhancer !== 'function') {
throw new Error('Expected the enhancer to be a function.')
}
// NOTE:enhancer正常情况
return enhancer(createStore)(reducer, preloadedState)
}
let currentReducer = reducer //NOTE:当前Reducer
let currentState = preloadedState //NOTE:当前State
let currentListeners = [] //NOTE:当前监听回调的数组
let nextListeners = currentListeners //NOTE:下一个监听回调的数组
// NOTE:保证可以修改下一个监听组的数据不出错,在需要使用到nextListeners的地方都需要进行处理;
function ensureCanMutateNextListeners() {
if (nextListeners === currentListeners) {
// NOTE:防止指针问题,返回了新的数组
nextListeners = currentListeners.slice()
}
}
// NOTE:返回当前整个Redux的State
function getState() {
return currentState
}
function subscribe(listener) {
ensureCanMutateNextListeners() // NOTE:确保nextListeners的准确性
nextListeners.push(listener) // NOTE:添加listener到nextListeners
// NOTE:返回解绑的回调,可以解除当前listener的监听;
return function unsubscribe() {
// NOTE:设置订阅状态,并将listener在nextListeners中剔除;
ensureCanMutateNextListeners()
const index = nextListeners.indexOf(listener)
nextListeners.splice(index, 1)
}
}
function dispatch(action) {
// NOTE:将dispatch状态修改,并且根据reducer里面注册好的的function,拿到dipacth的新state,设置为当前状态
try {
isDispatching = true
currentState = currentReducer(currentState, action)
} finally {
isDispatching = false
}
// NOTE:执行整个订阅的事件组
const listeners = (currentListeners = nextListeners)
for (let i = 0; i < listeners.length; i++) {
const listener = listeners[i]
listener()
}
return action
}
function replaceReducer(nextReducer) {
currentReducer = nextReducer
dispatch({ type: ActionTypes.REPLACE }) // NOTE:替换完成后dispatch
}
//NOTE:是一个第三方库,https://github.com/tc39/proposal-observable,主要用户对订阅的对象扩展处理
function observable() {
const outerSubscribe = subscribe
return {
subscribe(observer) {
function observeState() {
// NOTE:如subscribe(observer).filter(getState() => { dosomething }).map(getState() => { dosomething })
if (observer.next) {
observer.next(getState())
}
}
observeState()
const unsubscribe = outerSubscribe(observeState)
return { unsubscribe }
},
// NOTE:$$observable为一个Symbol对象
[$$observable]() {
return this
},
}
}
// NOTE:在创建Store时,dispatch一个初始化的Action
dispatch({ type: ActionTypes.INIT })
return {
dispatch,
subscribe,
getState,
replaceReducer,
[$$observable]: observable,
}
}
Compose
Compose 是值得大家去理解或者记住的
// NOTE:该方法主要是实现函数Curry化,并且通过reduce,将全部参数(function)从右到左执行,并且将执行后的return作为下一个的参数传入
export default function compose(...funcs) {
if (funcs.length === 0) {
return arg => arg
}
if (funcs.length === 1) {
return funcs[0]
}
/*
NOTE:reduce就是数组叠加,主要将funcs处理好
假设a、b、c都为function,compose则会处理成arg => a(b(c(arg))),这样一个function,compose(args)即可得到最终结果
*/
return funcs.reduce(
(a, b) =>
(...args) =>
a(b(...args))
)
}
combineReducers
export default function combineReducers(reducers) {
const reducerKeys = Object.keys(reducers)
const finalReducers = {}
for (let i = 0; i < reducerKeys.length; i++) {
const key = reducerKeys[i]
// NOTE:如果是正常的Reducer直接塞入finalReducers
if (typeof reducers[key] === 'function') {
finalReducers[key] = reducers[key]
}
}
const finalReducerKeys = Object.keys(finalReducers)
return function combination(state = {}, action) {
let hasChanged = false
const nextState = {}
// NOTE:拿到整个Reducers,然后拿到对应的Key,最后拿到key对应的reducer,然后传入state, action并执行reducer方法
for (let i = 0; i < finalReducerKeys.length; i++) {
const key = finalReducerKeys[i]
const reducer = finalReducers[key]
const previousStateForKey = state[key] //NOTE:获取当前Reduce对应的State
const nextStateForKey = reducer(previousStateForKey, action) //NOTE:获取传入action,Reduce对应的State
nextState[key] = nextStateForKey // NOTE:将更新后的State当道nextState对应的key中
hasChanged = hasChanged || nextStateForKey !== previousStateForKey
}
// NOTE:如果前后的State不等就return nextState,否则return state
return hasChanged ? nextState : state
}
}
bindActionCreators
// NOTE:将action和dispatch进行封装,方便用户直接定义变量使用
function bindActionCreator(actionCreator, dispatch) {
return function () {
return dispatch(actionCreator.apply(this, arguments))
}
}
export default function bindActionCreators(actionCreators, dispatch) {
/*
NOTE:如果是object,则进行遍历,对action里面的value为function的进行处理,主要是做actions的处理
{
userAction: () => { type, data },
homeAction: () => { type, data }
}
*/
const boundActionCreators = {}
for (const key in actionCreators) {
const actionCreator = actionCreators[key]
if (typeof actionCreator === 'function') {
boundActionCreators[key] = bindActionCreator(actionCreator, dispatch)
}
}
return boundActionCreators
}
applyMiddleware
export default function applyMiddleware(...middlewares) {
return createStore =>
(...args) => {
const store = createStore(...args)
// NOTE:中间件的Api,目前只要能拿到store的状态和将dispatch传递下去即可
const middlewareAPI = {
getState: store.getState,
dispatch: (...args) => dispatch(...args),
}
// NOTE:给每个中间件拿到Store
const chain = middlewares.map(middleware => middleware(middlewareAPI))
// NOTE:将所有中间件合并起来,从右往左处理,执行完的作为参数传给下一个中间件
dispatch = compose(...chain)(store.dispatch)
return { ...store, dispatch }
}
}
Flow
Redux Thunk
/**
* @param {object} extraArgument 主要是用户需要传递的参数
* return 一个curry的函数
*/
function createThunkMiddleware(extraArgument) {
/**
* NOTE:结合redux的applyMiddleware来看
* @param {({ dispatch, getState })} middlewareAPI { getState: store.getState, dispatch: (...args) => dispatch(...args) }
* @param { next } store.dispatch
* @param { action } any 可以是object或者function,由用户传入
*
* applyMiddleware将api的设置处理好,然后将store.dispatch传入
* 再return action => {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument)
}
return next(action)
}
用户的action如果传入的是function则将dispatch, getState, extraArgument传递并执行该方法,所以需要在该方法上去dispatch
如果传入的不是function则直接dispatch
*/
return ({ dispatch, getState }) =>
next =>
action => {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument)
}
return next(action)
}
}
// NOTE:默认的不使用extraArgument,需要增加参数的的直接使用thunk.withExtraArgument
const thunk = createThunkMiddleware()
thunk.withExtraArgument = createThunkMiddleware
export default thunk