阅读量:7
目录
接上篇文章:Redux中间件介绍。
1,applyMiddleware 原理
Redux 应用中间件方式:
const store = createStore(reducer, applyMiddleware(logger1, logger2));
实际会转为下面的方式执行:
const store = applyMiddleware(logger1, logger2)(createStore)(reducer)
applyMiddleware
会确定用到的中间件;它会返回一个用来创建仓库的函数A,参数是createStore
;- 函数 A,会返回创建仓库的函数B,和
createStore
函数差不多。 - 函数B,会对中间件函数做处理,并修改原始
dispatch
。
大致相当于:
export const applyMiddleware = (...middlewares) => { // 用来创建的仓库的函数 return (createStore) => { // 创建仓库的函数 return (reducer, defaultState) => { const store = createStore(reducer, defaultState) const dispatch = '经过 middlewares 处理的 store.dispatch' return { ...store, dispatch } } } }
2,实现
2.1,applyMiddleware
上篇文章介绍了 中间件函数 的写法和多个中间件函数的执行顺序。
基于此,实现这个 dispatch
流转的逻辑,并得到最终的 dispatch
即可完成 applyMiddleware
。
2.1.1,compose 方法
关键要实现
const resultDispatch = logger1(logger2(logger3(store.dispatch)))
实现:
/** * @param {...any} funcs * @returns {function} */ export const compose = (...funcs) => { if (funcs.length === 0) { return (args) => args; } else if (funcs.length === 1) { return funcs[0]; } return (...args) => { let lastReturn = null; for (let i = funcs.length - 1; i >= 0; i--) { const func = funcs[i]; if (i === funcs.length - 1) { lastReturn = func(...args); } else { lastReturn = func(lastReturn); } } return lastReturn; }; };
// 测试代码 const add = (n) => { return n + n; }; const mult = (n) => { return n * n; }; const b = compose(add, mult); console.log(b(3)); // 先乘后加,18
可使用 Array.reduce
简化:
export const compose = (...funcs) => funcs.reduce( (prev, next) => (...args) => prev(next(...args)) );
2.1.2,applyMiddleware
import { compose } from "./compose"; export const applyMiddleware = (...middlewares) => { return (createStore) => { return (reducer, defaultState) => { const store = createStore(reducer, defaultState); let dispatch = () => { throw new Error("目前还不能使用 dispatch"); }; // 传递给中间件函数的 store 只有这2个属性。 const simpleStore = { getState: store.getState, dispatch: (...args) => dispatch(...args), // 每个中间件函数的 dispatch 都是上一个中间件组装后的 }; // 获取用于创建 dispatch 的函数 const dispatchProducts = middlewares.map((m) => m(simpleStore)); // 重新组装后的 dispatch dispatch = compose(...dispatchProducts)(store.dispatch); return { ...store, dispatch, }; }; }; };
2.2,修改 createStore
之前实现的 createStore,没有对可能的第3个函数做处理。这里补充下:
- 如果第2个参数是
applyMiddleware
,那说明没有defaultState
。
这里就简单判断写第2个参数是不是函数,实际源码中
defaultState
也可以通过一个函数创建。
export const createStore = (reducer, defaultState, enhancer) => { // enhancer 表示 applymiddleware 返回的函数。 if (typeof defaultState === 'function') { enhancer = defaultState defaultState = undefined } if (typeof enhancer === 'function') { enhancer(createStore)(reducer, defaultState) } // 其他剩余代码没有做变动。 // ... }
完整代码
export const createStore = (reducer, defaultState, enhancer) => { // enhancer 表示 applymiddleware 返回的函数。 if (typeof defaultState === "function") { enhancer = defaultState; defaultState = undefined; } if (typeof enhancer === "function") { enhancer(createStore)(reducer, defaultState); } let currentReducer = reducer; let currentState = defaultState; let listeners = []; const dispatch = (action) => { if (typeof action !== "object" || Object.getPrototypeOf(action) !== Object.prototype) { throw new Error("action 必须是一个 plain Object"); } if (action.type === undefined) { throw new Error("action 必须有 type 属性"); } currentState = currentReducer(currentState, action); // 每次更新时,遍历监听器。 for (const listener of listeners) { listener(); } }; const getState = () => { return currentState; }; const subscribe = (listener) => { listeners.push(listener); let isRemove = false; // 取消监听 return () => { if (isRemove) { return; } else { isRemove = true; listeners = listeners.filter((f) => f !== listener); } }; }; // createStore 创建时会调用一次。 dispatch({ type: `@@redux/INIT${getRandomString}`, }); return { dispatch, getState, subscribe, }; }; function getRandomString() { return Math.random().toString(36).substring(2, 8).split("").join("."); }
以上。