IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> redux applyMiddleware源码解析、redux-thunk源码解析、redux-logger源码解析 -> 正文阅读

[JavaScript知识库]redux applyMiddleware源码解析、redux-thunk源码解析、redux-logger源码解析

中间件的思想和koa的洋葱模型类似,当遇到next时交给下一个中间件处理,当最后一个中间件处理完毕后,依次退回到上一个next之后执行
在这里插入图片描述
主要通过reduce将之后的函数作为参数传递给上一个函数,则上一个函数调用参数就会执行下一个函数,在下一个函数执行完后退回

export default function compose(...funcs) {
  if (funcs.length === 0) {
    return arg => arg
  }

  if (funcs.length === 1) {
    return funcs[0]
  }
	//当传递了多个函数时
  return funcs.reduce((a, b) => (...args) => a(b(...args)))
}
————————————————
  • 若传递的是compose(e,f,g) ,则第一次调用返回(…args) => e(f(…args))
  • 第二次调用,a为(…args) => e(f(…args)),b为g
  • 则最终调用结果为(…args) => e(f(g(…args)))

一个中间件格式示例:

function M1(store) {
  return function(next) {
    return function(action) {
      console.log('A middleware1 开始');
      next(action)
      console.log('B middleware1 结束');
    };
  };
}

applyMiddleware

  • 核心返回通过中间件改造后的dispatch
let store = applyMiddleware(loggerMiddleware)(createStore)(rootReducer);


export default function applyMiddleware(...middlewares) {            
	return (next)  => 
		(reducer, initialState) => {
			  //这里的next为createStore
              var store = next(reducer, initialState);
              var dispatch = store.dispatch;
              var chain = [];

              var middlewareAPI = {
                getState: store.getState,
                dispatch: (action) => dispatch(action)
              };

              chain = middlewares.map(middleware =>
                            middleware(middlewareAPI));
              dispatch = compose(...chain, store.dispatch);
              return {
                ...store,
                dispatch
              };
           };
}
  • chain的作用将store的getState方法、和改造的dispatch传给中间件,并返回第二层函数,chain = [(next)=>(action)=>{…}, (next)=>(action)=>{…}, (next)=>(action)=>{…}]
  • 传递改造后的disptach原因看下面的redux-thunk
  • compose的作用:compose(A, B, C, arg) === A(B(C(arg)))
  • 则最后一个中间件的next是store.dispatch这个操作store的原始方法
  • A的next是B的action方法,B的next是C的action方法,C的next是store.dipatch
  • 又因为A执行后为(action)=>{…},所以添加中间件改造后的dispatch传入的action,能够通过next传递给下一个中间件的(action)=>{…},最终通过最后一个中间件的next即store.dispatch传递给reducer
function M1(store) {
  return function(next) {
    return function(action) {
      console.log('A middleware1 开始');
      next(action)
      console.log('B middleware1 结束');
    };
  };
}

function M2(store) {
  return function(next) {
    return function(action) {
      console.log('C middleware2 开始');
      next(action)
      console.log('D middleware2 结束');
    };
  };
}

function M3(store) {
  return function(next) {
    return function(action) {
      console.log('E middleware3 开始');
      next(action)
      console.log('F middleware3 结束');
    };
  };
}
  
function reducer(state, action) {
  if (action.type === 'MIDDLEWARE_TEST') {
    console.log('======= G =======');  
  }
  return {};
}

react-thunk
基本使用

export const increment=(num)=>({type:INCREMENT,data:num})
//异步action返回函数
export const incrementAsync=(num)=>{return dispatch=>{
    setTimeout(()=>{
        dispatch(increment(num))
    },1000)
}}

...
this.props.incrementAsync(num);
function createThunkMiddleware(extraArgument) {
  return ({ dispatch, getState }) => next => action => {
    if (typeof action === 'function') {
      return action(dispatch, getState, extraArgument);
    }

    return next(action);
  };
}

  • 因为这里使用了react-redux高阶函数this.props.incrementAsync(num)的调用,相当于改造的dispatch(incrementAsync(num))
  • dispatch即为createThunkMiddleware中的action函数,当调用时,因为参数action为一个函数,即
dispatch=>{
    setTimeout(()=>{
        dispatch(increment(num))
    },1000)
}
  • 所以会走action(dispatch, getState, extraArgument)
  • 将改造后的dispatch传递进去,又因为在这里改造后的dispatch就是createThunkMiddleware中的action函数,所以调用时又回去了,不过此时if判断中action不再是一个函数,而是一个{type:…}对象,所以此时会走next(action)交给下一个中间件处理
  • 这也是为什么传递给中间件的dispatch是改造后的dispatch的原因,因为在redux-thunk中会调用一次重新走中间件的流程
  • redux-thunk的异步处理其实就是在异步任务中调用dispatch,和同步任务没啥区别,纯属脱了裤子放屁。。。

redux-logger

  • redux-logger建议放在中间件的最后一位是因为最后一位能保证next为store.dispatch而非改造后的dispatch,所以使用store.dispatch更新store能准确快速拿到更新后的state
export default function createLogger({ getState }) {
      return (next) => 
        (action) => {
              const console = window.console;
              const prevState = getState();
              const returnValue = next(action);
              const nextState = getState();
              const actionType = String(action.type);
              const message = `action ${actionType}`;

              console.log(`%c prev state`, `color: #9E9E9E`, prevState);
              console.log(`%c action`, `color: #03A9F4`, action);
              console.log(`%c next state`, `color: #4CAF50`, nextState);
              return returnValue;
    };
}
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-02-07 13:38:22  更:2022-02-07 13:39:19 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 11:00:46-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码