您的位置:首页 > 房产 > 建筑 > React@16.x(60)Redux@4.x(9)- 实现 applyMiddleware

React@16.x(60)Redux@4.x(9)- 实现 applyMiddleware

2024/10/7 10:21:10 来源:https://blog.csdn.net/qq_40147756/article/details/140393631  浏览:    关键词:React@16.x(60)Redux@4.x(9)- 实现 applyMiddleware

目录

  • 1,applyMiddleware 原理
  • 2,实现
    • 2.1,applyMiddleware
      • 2.1.1,compose 方法
      • 2.1.2,applyMiddleware
    • 2.2,修改 createStore

接上篇文章: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));// 重新组装后的 dispatchdispatch = 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 = defaultStatedefaultState = 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(".");
}

以上。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com