当前位置: 首页 > news >正文

redux中间件函数

middleware中间件函数

中间件本质就是得到一个新的dispatch创建函数,调用创建函数,重写了store.dispatch(action),依次执行新的dispatch(action)方法,来改变store中的state
我们从一个小案例来说明中间件函数的由来:

我们需要记录一下操作类型action和下一个状态state

//由action创建函数addTodo创建一个action对象
const action = addTodo('Use Redux')
//打印action对象
console.log('dispatching', action)
store.dispatch(action)
//打印下一个状态
console.log('next state', store.getState())

这是我们想要的效果,但不想每次都这样做手动创建,我们希望用一个函数来自动创建

封装dispatch函数

将日志记录提取到函数中:


function dispatch(store, action) {
  console.log('dispatching', action)
  store.dispatch(action)
  console.log('next state', store.getState())
}

然后,在任何地方使用它,而不是store.dispatch():

dispatch(store, addTodo('Use Redux'))

我们可以到这里结束,但是每次都导入一个特殊的函数不是很方便。

使用 Monkeypatching (猴子补丁)重写dispatch方法

Monkeypatching 是一种黑客攻击。“替换任何你喜欢的方法”

const next = store.dispatch  //保存源dispatch
//重写dispatch
store.dispatch = function dispatch(action) {
  console.log('dispatching', action)
  let result = next(action)   //调用原始的dispatch方法
  console.log('next state', store.getState())
  return result
}

同样,我们我们也使用一个函数封装一下,这样我们就不用每次都是编写一遍,这样就是一个中间件雏形了

function logMiddileware(store) {
const next = store.dispatch  //保存源dispatch
//重写dispatch
store.dispatch = function dispatch(action) {
  console.log('dispatching', action)
   //调用原始的dispatch方法,相当于store.dispatch(action)
   //store.dispatch(action)返回结果是当前action对象
  let result = next(action)  
  console.log('next state', store.getState())
  return result
}
}

这已经更接近我们想要的了!无论我们在哪里调度一个动作,它都保证被记录。但总感觉哪里不对

使用多个 Monkeypatching (猴子补丁)重写dispatch方法

增加一个错误报告

function logMiddileware(store) {
  const next = store.dispatch
  store.dispatch = function dispatch(action) {
    console.log('dispatching', action)
    let result = next(action)
    console.log('next state', store.getState())
    return result
  }
}

function errorMiddileware(store) {
  const next = store.dispatch
  store.dispatch = function dispatch(action) {
    try {
      return next(action)
    } catch (err) {
      console.error('Caught an exception!', err)
      Raven.captureException(err, {
        extra: {
          action,
          state: store.getState()
        }
      })
      throw err
    }
  }
}

logMiddileware(store)
errorMiddileware(store)

不过,这并不好,感觉怪怪的,我们使用dispatch传递的参数是action,这里传递的是store,就让人有些疑惑,所以我们希望返回一个封装后的dispatch函数。

function logMiddileware(store) {
  const next = store.dispatch
  // 之前是直接将store.dispatch重写
  // store.dispatch = function dispatch(action) {}

  return function (action) {
    console.log('dispatching', action)
    let result = next(action)
    console.log('next state', store.getState())
    return result
  }
}
let  dispatch=store.dispatch(store)
	 dispatch(action)   

但是我们调用logger函数是还是要传递store对象,不是我们想要的,所以我们使用一个辅助函数来实现我们想要的store.dispatch(action)

//我们在这里传递store
function applyMiddlewareByMonkeypatching(store, middlewares) {
  middlewares = middlewares.slice()
  middlewares.reverse()
  
  //在这里重写了store.dispatch
  middlewares.forEach(middleware => (store.dispatch = middleware(store)))
}

这样我们就可以直接调用store.dispatch(action)
但是

 middlewares.forEach(middleware => (store.dispatch = middleware(store)))

store.dispatch(action)还是被重写了,
为什么我们还是要在applyMiddlewareByMonkeypatching中重写store.dispatch,这样目的是使每个中间件都能调用store.dispatch,这样中间件都被链接起来了,但是,它仍然是猴子补丁,我们要想办法解决。

修改中间件

function logMiddileware(store) {
//返回一个dispatch创建函数,这样我们就可以接收store.dispatch当做参数
  return function dispatchCreator(dispatch) {
    return function dispatch(action) {
      console.log('dispatching', action)
      let result = next(action)
      console.log('next state', store.getState())
      return result
    }
  }
}

使用箭头函数更加精简

const logMiddileware = store => dispatch => action => {
  console.log('dispatching', action)
  let result = next(action)
  console.log('next state', store.getState())
  return result
}

我们通常会把dispatch函数用next来命名

const logMiddileware = store => next => action => {
  console.log('dispatching', action)
  let result = next(action)
  console.log('next state', store.getState())
  return result
}

修改applyMiddlewareByMonkeypatching辅助函数

我们把applyMiddlewareByMonkeypatching辅助函数修改一下,变成下面这个样子:

function applyMiddleware(store, middlewares) {
  middlewares = middlewares.slice()
  middlewares.reverse()
  let dispatch = store.dispatch

  middlewares.forEach(middleware => (dispatch = middleware(store)(dispatch)))
  return Object.assign({}, store, { dispatch })
}

注意这里,我们先声明了变量dispatch,然后将store.dispatch赋值给他,这样dispatch 是当做参数被传递进去,没有被重写

  let dispatch = store.dispatch
 middlewares.forEach(middleware => (dispatch = middleware(store)(dispatch)))
  • 第一次传递的dispatch是原始的store.dispatch
  • middleware(store)返回dispatch创建函数dispatchCreator,再调用创建函数dispatchCreator(dispatch),然后在返回dispatch函数,每次循环的时候他会把上一个dispatch函数传给下一个中间件函数,依次从外到内传递下去,直到最后一个。
  • 最后一个中间件运行的会调用传递的dispatch(action),然后又依次从内到外运行dispatch(action)

相关文章:

  • 【前端面试知识题】- 4.1 JavaScript
  • 客户端架构
  • iOS Xcode 14 创建新项目Pod init及Pod install 报错
  • 金融行业借力泛微今承达,合同统一数字化管理、风险全过程把控
  • 计算机视觉项目实战-基于特征点匹配的图像拼接
  • 软件过程与建模学习之:Individuals,Motivation and Teams
  • 【某南方·高中梦校面试】
  • 三分钟细数几款可视化前端开发工具
  • 【定制项目】【M15 消防安全宣传】主要模块:视频 + 音频 + 图标 + 问答游戏
  • 计算机毕业设计-基于协同过滤算法的旅游管理系统-基于SSM的旅游定制系统(源码+讲解+文档)
  • 蓝凌OA漏洞分析与处置方案
  • JAVA基础(四十五)——集合之Map接口
  • Python+审计实务与案例分析库 毕业设计-附源码211526
  • ES6--》对象扩展方法
  • 安卓在任意位置打开drawerLayout
  • JS中 map, filter, some, every, forEach, for in, for of 用法总结
  • ECMAScript 6 学习之路 ( 四 ) String 字符串扩展
  • ECMAScript6(0):ES6简明参考手册
  • Java Agent 学习笔记
  • js ES6 求数组的交集,并集,还有差集
  • Linux gpio口使用方法
  • Nodejs和JavaWeb协助开发
  • Python socket服务器端、客户端传送信息
  • python大佬养成计划----difflib模块
  • Webpack入门之遇到的那些坑,系列示例Demo
  • 大整数乘法-表格法
  • 技术:超级实用的电脑小技巧
  • 面试题:给你个id,去拿到name,多叉树遍历
  • 如何邀请好友注册您的网站(模拟百度网盘)
  • Semaphore
  • ​Distil-Whisper:比Whisper快6倍,体积小50%的语音识别模型
  • ​LeetCode解法汇总518. 零钱兑换 II
  • ​Python 3 新特性:类型注解
  • ​如何使用ArcGIS Pro制作渐变河流效果
  • (附源码)springboot高校宿舍交电费系统 毕业设计031552
  • (附源码)springboot家庭财务分析系统 毕业设计641323
  • (附源码)计算机毕业设计SSM智慧停车系统
  • (转) RFS+AutoItLibrary测试web对话框
  • (转)visual stdio 书签功能介绍
  • (最简单,详细,直接上手)uniapp/vue中英文多语言切换
  • .NET Core 实现 Redis 批量查询指定格式的Key
  • .NET Core跨平台微服务学习资源
  • .NET Standard 的管理策略
  • .NET:自动将请求参数绑定到ASPX、ASHX和MVC(菜鸟必看)
  • .Net转Java自学之路—基础巩固篇十三(集合)
  • ::
  • []sim300 GPRS数据收发程序
  • [1] 平面(Plane)图形的生成算法
  • [202209]mysql8.0 双主集群搭建 亲测可用
  • [C#]winform制作仪表盘好用的表盘控件和使用方法
  • [C++核心编程](四):类和对象——封装
  • [Golang]K-V存储引擎的学习 从零实现 (RoseDB mini版本)
  • [hadoop读书笔记] 第十五章 sqoop1.4.6小实验 - 将mysq数据导入HBASE
  • [HNOI2010]BUS 公交线路
  • [IE技巧] 使IE8以单进程的模式运行