如何理解redux的middleware中间件

如何理解redux的middleware中间件

如果需要在dispatch前后分别打印出action,和action后的state,我们需要怎么做
实现方案如下:
首先我们想到在前后分别添加console,每次调用都在调用前后加console

  1. 在每次dispatch前后加console

    console.log("start ",action)
    store.dispatch(action)
    console.log("end ",store.getState())

    但是这样每一次调用都要多写两行代码,总的来说会出现很多console,最容易想到的就是把这段代码封装到一个函数里,每次需要的时候调用函数即可

  2. 定义成方法,在需要dispatch时调用方法

    function dispatchAndLog(store,action){
      console.log("start ",action)
      store.dispatch(action)
      console.log("end ",store.getState())
    }

    调用dispatch的地方改为调用如下代码

    dispatchAndLog(store,action)

    这样来说貌似可以了,但是每次都调用一个非api方法,新人不易理解,还是应该调用原有api,然后又有了修改dispatch的方案

  3. 修改认的dispatch方法
    在以后的调用中直接调用store.dispatch即可

    const next = store.dispatch
    store.dispatch = fuction dispatchAndLog(store,action)
      let result = next(action)
      console.log("end ",store.getState())
      return result
    }

    这样看起来蛮好的,但是如果我现在不仅需要这一个打印日志的功能还需要一个能提供报错信息的功能
    我们可能想到如下方案

  4. 添加出错报告功能

    function patchStoretoAddLog(store,action){
      const next = store.dispatch
      store.dispatch = function dispatchAndLog(store,action){
        console.log("start ",action)
        let result = next(action)
        console.log("end ",store.getState())
        return result
      }
    }
    
    function patchStoretoAddCrashReporting(store,action){
      const next = store.dispatch
      store.dispatch = function dispatchAndCrashReporting(store,action){
        try {
          return next(action)
        } catch (err) {
          console.error('Caught an exception!',err)
          // 把错误信息发送到其他监控系统
           throw err
        }
      }
    }

    这样即要日志,又要报错的时候依次调用两个函数即可

    patchStoretoAddLog(store,action)
    patchStoretoAddCrashReporting(store,action)

    这样还是原来问题每次调用都要写两个,麻烦
    更好方案如下:

  5. 使用一个功能返回一个函数,返回的函数用于处理插件的逻辑

    function logger(store) {
      const next = store.dispatch
      // PrevIoUsly:
      // store.dispatch = function dispatchAndLog(action) {
      return function dispatchAndLog(action) {
        console.log('dispatching',action)
        let result = next(action)
        console.log('next state',store.getState())
        return result;
      }
    }
    function crashReporting(store){
      const next = store.dispatch
      return function dispatchAndCrashReporting(action){
        try {
          return next(action)
        } catch (err) {
          console.error('Caught an exception!',err)
          // 把错误信息发送到其他监控系统
           throw err
        }
      }
    }

    调用方法如下

    logger(store)(action)
    crashReporting(store)(action)

    仔细观察其实是有规律的,可以写一个函数来遍历执行所有的插件

    function applyMiddlewareByMonkeypatching(store,middlewares){
       middlewares = middlewares.slice()
       middlewares.reverse() //确保卸载后面的插件包在里面,后面执行
       middlewares.forEach(middleware=>
        //每一个middleware都可以直接调用一个 middleware 包装过的 store.dispatch
         store.dispatch = middleware(store)
       )
    }

    调用如下

    applyMiddlewareByMonkeypatching(store,[logger,crashReporting])

    等于如下代码

    // according to https://redux.js.org/api-reference/store#dispatch
    // store.dispatch(action) 返回新的state 即新的store
    store.dispatch = logger(crashReporting(store))
    //也就等同于如下代码
    store.dispatch = function dispatchAndLog(action) {
      console.log('dispatching',action)
      let result = function dispatchAndCrashReporting(action){
        try {
          return next(action)
        } catch (err) {
          console.error('Caught an exception!',err)
          // 把错误信息发送到其他监控系统
           throw err
        }
      }
      console.log('next state',store.getState())
      return result;
    }

    这种方法已经很好了,但是它依旧是修改原来的store.dispatch方法,我们可以想办法不修改认的store.dispatch方法

  6. 更进一步

    function logger(store) {
      return function wrapperdispatchAndLog(next){
        return function dispatchAndLog(action) {
          console.log('dispatching',action)
          let result = next(action)
          console.log('next state',store.getState())
          return result;
        }
      }
    }
    // es6写法
    const logger = store => next => action => {
          console.log('dispatching',store.getState())
          return result;
        }
      }
    }
    // 修改遍历函数
    function applyMiddleware (store,middlewares){
      middlewares = middlewares.splice()
      middlewares.reverse()
      let dispatch = store.dispatch
      middlewares.forEach(middleware=>{
        dispatch = middleware(store)(dispatch)
      })
      return Object.assign({},store,dispatch)
    }
    // 调用方法 
    // 返回经过middleware包装过的含有新dispatch的store
    applyMiddleware(store,crashReporting])

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如果组件之中有复用的代码,需要重新创建一个父类,父类中存储公共代码,返回子类,同时把公用属性...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例如我们的 setState 函数式同步执行的,我们的事件处理直接绑定在了 dom 元素上,这些都跟 re...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom 转为真实 dom 进行挂载。其实函数是组件和类组件也是在这个基础上包裹了一层,一个是调...
react 本身提供了克隆组件的方法,但是平时开发中可能很少使用,可能是不了解。我公司的项目就没有使用,但是在很多三方库中都有使用。本小节我们来学习下如果使用该...
mobx 是一个简单可扩展的状态管理库,中文官网链接。小编在接触 react 就一直使用 mobx 库,上手简单不复杂。
我们在平常的开发中不可避免的会有很多列表渲染逻辑,在 pc 端可以使用分页进行渲染数限制,在移动端可以使用下拉加载更多。但是对于大量的列表渲染,特别像有实时数据...
本小节开始前,我们先答复下一个同学的问题。上一小节发布后,有小伙伴后台来信问到:‘小编你只讲了类组件中怎么使用 ref,那在函数式组件中怎么使用呢?’。确实我们...
上一小节我们了解了固定高度的滚动列表实现,因为是固定高度所以容器总高度和每个元素的 size、offset 很容易得到,这种场景也适合我们常见的大部分场景,例如...
上一小节我们处理了 setState 的批量更新机制,但是我们有两个遗漏点,一个是源码中的 setState 可以传入函数,同时 setState 可以传入第二...
我们知道 react 进行页面渲染或者刷新的时候,会从根节点到子节点全部执行一遍,即使子组件中没有状态的改变,也会执行。这就造成了性能不必要的浪费。之前我们了解...
在平时工作中的某些场景下,你可能想在整个组件树中传递数据,但却不想手动地通过 props 属性在每一层传递属性,contextAPI 应用而生。
楼主最近入职新单位了,恰好新单位使用的技术栈是 react,因为之前一直进行的是 vue2/vue3 和小程序开发,对于这些技术栈实现机制也有一些了解,最少面试...
我们上一节了了解了函数式组件和类组件的处理方式,本质就是处理基于 babel 处理后的 type 类型,最后还是要处理虚拟 dom。本小节我们学习下组件的更新机...
前面几节我们学习了解了 react 的渲染机制和生命周期,本节我们正式进入基本面试必考的核心地带 -- diff 算法,了解如何优化和复用 dom 操作的,还有...
我们在之前已经学习过 react 生命周期,但是在 16 版本中 will 类的生命周期进行了废除,虽然依然可以用,但是需要加上 UNSAFE 开头,表示是不安...
上一小节我们学习了 react 中类组件的优化方式,对于 hooks 为主流的函数式编程,react 也提供了优化方式 memo 方法,本小节我们来了解下它的用...
开源不易,感谢你的支持,❤ star me if you like concent ^_^
hel-micro,模块联邦sdk化,免构建、热更新、工具链无关的微模块方案 ,欢迎关注与了解
本文主题围绕concent的setup和react的五把钩子来展开,既然提到了setup就离不开composition api这个关键词,准确的说setup是由...
ReactsetState的执行是异步还是同步官方文档是这么说的setState()doesnotalwaysimmediatelyupdatethecomponent.Itmaybatchordefertheupdateuntillater.Thismakesreadingthis.staterightaftercallingsetState()apotentialpitfall.Instead,usecom