本文redux源码主要围绕从一个stroe的创建到所有核心API充分利用运行的角度来分析
createStore
- createStore是redux的核心,主要方法有getState、dispach、subscribe
- createStore的主要功能就是创建store,处理View对action的触发,完成reduce返回新的state值进行保存以及更新store状态
创建store
createStore主要接收3个参数:reduce, preloadState, enhancer.
- reduce是外部传入触发action以后的逻辑处理方法
- preloadState是默认的state
- enhancer如词本意,就是用于增强store
createStore函数通过接收preloadState作为currentState默认值,View可以通过getState获取currentState状态,然后通过dispatch调用readuce处理action触发的逻辑并返回一个新的state用currentState保存起来.最后用subscribe方法订阅store,当store状态发生改变的时候可以获取最新的store状态并进行逻辑处理
如下图所示:
// 建立redux模型function createStore(reduce, preloadState, enhancer) {//接收默认statelet currentState = preloadState//订阅队列let curentListeners = [];// 获取状态function getState() {return currentState}// 触发actionfunction dispatch(action) {//处理reducecurrentState = reduce(currentState, action)//每一个订阅者都可以通过此回调获取最新storefor (let i = 0; i < curentListeners.length; i++) {let listener = curentListeners[i];listener()}}//订阅状态function subscribe(listener) {curentListeners.push(listener)}// 返回所有的核心方法return {getState,dispatch,subscribe,}}
createStore添加参数约束
为了避免开发者调用的出现类型错误导致的页面崩溃,一般的底层代码都会做类型判断处理,针对reduce做了一个简单的是否为函数判断处理
isPlainObject函数是用来判断action是否为对象的处理函数,因为action有可能传入null 或者是对象和数组,单纯的判断是否为object已经不能区分数组了,我们通过Object.getPrototypeOf方法查找上一级的逻辑运算,直到找到最上一级再与obj本身对比..如果全等就是对象
如下图所示:
// 建立redux模型function createStore(reduce, preloadState, enhancer) {let currentState = preloadStatelet curentListeners = [];// 判断reduce是否为函数if (typeof reduce !== "function") {throw Error("reduce 必须是一个函数")}....// 触发actionfunction dispatch(action) {// 判断action是否为对象if (!isPlainObject(action)) throw Error("action 必须是一个对象");if (typeof action.type === "undefined") throw Error("action 必须有type属性");currentState = reduce(currentState, action)for (let i = 0; i < curentListeners.length; i++) {let listener = curentListeners[i];listener()}}// 返回所有的核心方法return {getState,dispatch,subscribe,}}// 判断是否为对象function isPlainObject(obj) {// 非对象或为空直接返回falseif (typeof obj !== "object" || obj === null) return false// 区分数组和对象let proto = obj// 循环查找上一级直到没有为止while (Object.getPrototypeOf(proto) !== null) {proto = Object.getPrototypeOf(proto)}// 如果最后一级跟第一级相等,则为对象return proto === Object.getPrototypeOf(obj)}
Enhancer
Enhancer是用于增强createStore,可以让createStore的调用者对返回Store对象进行功能上的增强(类似于thunk,saga等插件的增强效果)
Enhancer的基本逻辑其实很简单,就是通过判断action的类型来处理,总共两种情况:
- action是函数,此时调用action方法传入disptch函数(外部操作执行完成之后利用返回的dispathc参数继续调用dispatch方法)
- action是对象则是正常调用dispatch方法传入action即可
代码如下图所示:
// 建立redux模型function createStore(reduce, preloadState, enhancer) {....// 判断enhancer是否为空if (typeof enhancer !== "undefined") {if (typeof enhancer !== "function") {throw Error("enhancer 必须是一个函数")}// 调用enhancer传入state和reducereturn enhancer(createStore)(reduce, preloadState)}....// 返回所有的核心方法return {getState,dispatch,subscribe,}}// action逻辑处理函数(中间件)function enhancer(createStore) {return function (reduce, preloadState) {const store = createStore(reduce, preloadState)let dispatch = store.dispatchfunction _dispatch(action) {if (typeof action === "function") {// action(dispatch)return action(dispatch)}dispatch(action)}return {...store,dispatch: _dispatch}}}
applymiddleware
- applymiddleware本质上跟enhancer的性质相同,都是为了增强dispatch的能力
- applymiddleware是redux为了处理单个或多个中间件组合的函数,让中间件按照顺序依次执行,当View上触发了action之后会先被中间件接收到,经过一个或者多个的中间件处理之后,action才会被传递给reduce进行处理
具体代码如下图所示:
// 处理中间件function applymiddleware(...middlewares) {return function (createStore) {return function (reduce, preloadState) {// 创建Storeconst store = createStore(reduce, preloadState)// 用于中间件处理的storeconst StoreAPI = {dispatch: store.dispatch,getState: store.getState,}const chain = middlewares.map(middleware => middleware(StoreAPI))//得到第一层的中间件方法let dispatch = compose(...chain)(store.dispatch)return {...store,dispatch: dispatch}}}}// 处理中间件的函数嵌套function compose() {var funcs = [...arguments];return function (dispatch) {// 反推loger(也就是上一层中间件)的next参数,其实就是最后一层thunk的最后一层函数for (var i = funcs.length - 1; i >= 0; i--) {dispatch = funcs[i](dispatch)}return dispatch;}}
bindActionCreatetors
- bindActionCreatetors的主要用途是将ActionCreatetor函数转换为能够触发action的函数
- bindActionCreatetors有2个参数第一个是ActionCreatetor函数对象,包含了单个或者多个ActionCreatetor函数,第二个是dispatch,用于触发action
bindActionCreatetors具体实现代码如下:
// bindActionCreatetors函数实现
function bindActionCreatetors(ActionCretors, dispatch) {
//用于保存要触发action
let bindActionCreatetorsobj = {};
for (let i in ActionCretors) {
bindActionCreatetorsobj[i] = () => {3
dispatch(ActionCretors[i]())
}
}
return bindActionCreatetorsobj;
}
combineReducers
- 用于组合reduce,将零碎的小reduce组合起来变成一个大的reduce
- 便于管理reduce零碎的state状态
代码如下图所示:
// 组合小的reduce成一个大的reduce
function combineReducers(reducers) {
// 判断每一个reduces的类型必须为函数
let reducerKeys = Object.keys(reducers)
for (let i = 0; i <= reducerKeys.length - 1; i++) {
let key = reducerKeys[i]
if (typeof reducers[key] !== "function") throw Error("reduce必须是一个函数")
}
return function (state, action) {
//state对象,用于存储每个reduce的值
var nextState = {};
for (var i = 0; i < reducerKeys.length; i++) {
var key = reducerKeys[i];
var reducer = reducers[key];
var previousStateForKey = state[key];
//拿到最新的state值
nextState[key] = reducer(previousStateForKey, action)
}
//返回最新的state状态对象
return nextState;
}
}
本文源代码以及编写流程:https://gitee.com/xielingyun879475908/my-redux
