8 redux Middleware(中间件)

本文探讨了如何通过构建Middleware解决记录日志和创建崩溃报告的问题,展示了从分析问题到解决方案的思维过程,介绍了Middleware的基本概念及其在Redux中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

理解 Middleware

正因为 middleware 可以完成包括异步 API 调用在内的各种事情。我们将以记录日志和创建崩溃报告为例,引导你体会从分析问题到通过构建 middleware 解决问题的思维过程。

 

问题: 记录日志

每次state更新时,如何记录其值

尝试 #1: 手动记录

let action = addTodo('Use Redux')

 

console.log('dispatching', action)

store.dispatch(action)

console.log('next state', store.getState())

 

尝试 #2: 封装 Dispatch

你可以将上面的操作抽取成一个函数:

function dispatchAndLog(store, action) {

  console.log('dispatching', action)

  store.dispatch(action)

  console.log('next state', store.getState())

}

然后用它替换 store.dispatch():

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

 

尝试 #3: Monkeypatching Dispatch

重写我们的dispatch

let next = store.dispatch

store.dispatch = function dispatchAndLog(action) {

  console.log('dispatching', action)

  // 调用原来的 dispatch

  let result = next(action)

  console.log('next state', store.getState())

  return result

}

 

问题: 崩溃报告

按照如上想法,我们添加崩溃报告的处理

function patchStoreToAddLogging(store) {

  let next = store.dispatch

  store.dispatch = function dispatchAndLog(action) {

    console.log('dispatching', action)

    let result = next(action)

    console.log('next state', store.getState())

    return result

  }

}

 

function patchStoreToAddCrashReporting(store) {

  let next = store.dispatch

  store.dispatch = function dispatchAndReportErrors(action) {

    try {

      return next(action)

    } catch (err) {

      console.error('捕获一个异常!', err)

      Raven.captureException(err, {

        extra: {

          action,

          state: store.getState()

        }

      })

      throw err

    }

  }}

 

尝试 #4: 隐藏 Monkeypatching

现在我们不直接更改store.dispatch,而是返回一个新的dispatch,此时我们可以称我们的方法为“中间件”

function logger(store) {

  let next = store.dispatch

 

  return function dispatchAndLog(action) {

    console.log('dispatching', action)

    let result = next(action)

    console.log('next state', store.getState())

    return result

  }

}

 

新建一个方法,叫做“应用中间件”,接收 store 和 中间件数组

function applyMiddlewareByMonkeypatching(store, middlewares) {

  middlewares = middlewares.slice()

  middlewares.reverse()

 

  // 在每一个 middleware 中变换 dispatch 方法。

  middlewares.forEach(middleware =>

    // 调用中间件,每个中间件都返回一个新的dispatch

    store.dispatch = middleware(store)

  )

}

 

然后像这样应用多个 middleware:

applyMiddlewareByMonkeypatching(store, [ logger, crashReporter ])

 

尝试 #5: 移除 Monkeypatching

ES6 的箭头函数可以使其 柯里化 ,从而看起来更舒服一些:

const logger = store => next => action => {

  console.log('dispatching', action)

  let result = next(action)

  console.log('next state', store.getState())

  return result

}

 

const crashReporter = store => next => action => {

  try {

    return next(action)

  } catch (err) {

    console.error('Caught an exception!', err)

    Raven.captureException(err, {

      extra: {

        action,

        state: store.getState()

      }

    })

    throw err

  }

}

这正是 Redux middleware 的样子。

Middleware 接收了一个参数 next 其本身是 dispatch 函数,并返回一个新的 dispatch 函数,返回的函数会被作为下一个 middleware 的 next()

不明白柯里化函数,如下,这样写应该会明白

store => next => action => {...}

store => {

    return (next => {

        return (action => {

            ...

        })

    })

}

 

尝试 #6: “单纯”地使用 Middleware

写一个 applyMiddleware 方法替换原来的 applyMiddlewareByMonkeypatching

// 警告:这只是一种“单纯”的实现方式!// 这 *并不是* Redux 的 API.

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 })

}

这与 Redux 中 applyMiddleware() 的实现已经很接近了

 

使用Redux的applyMiddleware

Redux的applyMiddleware原理就是我们所编写的applyMiddleware

import { createStore, combineReducers, applyMiddleware } from 'redux'

let todoApp = combineReducers(reducers)

let store = createStore(

  todoApp,

  // applyMiddleware() 告诉 createStore() 如何处理中间件

  applyMiddleware(logger, crashReporter))

 

就是这样!现在任何被发送到 store 的 action 都会经过 logger 和 crashReporter

// 将经过 logger 和 crashReporter 两个 middleware!

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值