applyMiddleware(...middlewares)

使用包含自定义功能的 middleware 来扩展 Redux 是一种推荐的方式。Middleware 可以让你包装 store 的dispatch 方法来达到你想要的目的。同时, middleware 还拥有“可组合”这一关键特性。多个 middleware 可以被组合到一起使用,形成 middleware 链。其中,每个 middleware 都不需要关心链中它前后的 middleware 的任何信息。

Middleware 最常见的使用场景是无需引用大量代码或依赖类似 Rx 的第三方库实现异步 actions。这种方式可以让你像 dispatch 一般的 actions 那样 dispatch 异步 actions。

例如,redux-thunk 支持 dispatch function,以此让 action creator 控制反转。被 dispatch 的 function 会接收 dispatch 作为参数,并且可以异步调用它。这类的 function 就称为 thunk。另一个 middleware 的示例是 redux-promise。它支持 dispatch 一个异步的 Promise action,并且在 Promise resolve 后可以 dispatch 一个普通的 action。

Middleware 并不需要和 createStore 绑在一起使用,也不是 Redux 架构的基础组成部分,但它带来的益处让我们认为有必要在 Redux 核心中包含对它的支持。因此,虽然不同的 middleware 可能在易用性和用法上有所不同,它仍被作为扩展 dispatch 的唯一标准的方式。

参数

  • ...middlewares (arguments): 遵循 Redux middleware API 的函数。每个 middleware 接受 Store 的dispatch 和 getState 函数作为命名参数,并返回一个函数。该函数会被传入 被称为 next 的下一个 middleware 的 dispatch 方法,并返回一个接收 action 的新函数,这个函数可以直接调用next(action),或者在其他需要的时刻调用,甚至根本不去调用它。调用链中最后一个 middleware 会接受真实的 store 的 dispatch 方法作为 next 参数,并借此结束调用链。所以,middleware 的函数签名是 ({ getState, dispatch }) => next => action

返回值

(Function) 一个应用了 middleware 后的 store enhancer。这个 store enhancer 就是一个函数,并且需要应用到 createStore。它会返回一个应用了 middleware 的新的 createStore

示例: 自定义 Logger Middleware

 1 import { createStore, applyMiddleware } from 'redux'
 2 import todos from './reducers'
 3
 4 function logger({ getState }) {
 5   return (next) => (action) => {
 6     console.log('will dispatch', action)
 7
 8     // 调用 middleware 链中下一个 middleware 的 dispatch。
 9     let returnValue = next(action)
10
11     console.log('state after dispatch', getState())
12
13     // 一般会是 action 本身,除非
14     // 后面的 middleware 修改了它。
15     return returnValue
16   }
17 }
18
19 let createStoreWithMiddleware = applyMiddleware(logger)(createStore)
20 let store = createStoreWithMiddleware(todos, [ 'Use Redux' ])
21
22 store.dispatch({
23   type: 'ADD_TODO',
24   text: 'Understand the middleware'
25 })
26 // (将打印如下信息:)
27 // will dispatch: { type: 'ADD_TODO', text: 'Understand the middleware' }
28 // state after dispatch: [ 'Use Redux', 'Understand the middleware' ]

View Code

示例: 使用 Thunk Middleware 来做异步 Action

  1 import { createStore, combineReducers, applyMiddleware } from 'redux'
  2 import thunk from 'redux-thunk'
  3 import * as reducers from './reducers'
  4
  5 // 调用 applyMiddleware,使用 middleware 增强 createStore:
  6 let createStoreWithMiddleware = applyMiddleware(thunk)(createStore)
  7
  8 // 像原生 createStore 一样使用。
  9 let reducer = combineReducers(reducers)
 10 let store = createStoreWithMiddleware(reducer)
 11
 12 function fetchSecretSauce() {
 13   return fetch('https://www.google.com/search?q=secret+sauce')
 14 }
 15
 16 // 这些是你已熟悉的普通 action creator。
 17 // 它们返回的 action 不需要任何 middleware 就能被 dispatch。
 18 // 但是,他们只表达「事实」,并不表达「异步数据流」
 19
 20 function makeASandwich(forPerson, secretSauce) {
 21   return {
 22     type: 'MAKE_SANDWICH',
 23     forPerson,
 24     secretSauce
 25   }
 26 }
 27
 28 function apologize(fromPerson, toPerson, error) {
 29   return {
 30     type: 'APOLOGIZE',
 31     fromPerson,
 32     toPerson,
 33     error
 34   }
 35 }
 36
 37 function withdrawMoney(amount) {
 38   return {
 39     type: 'WITHDRAW',
 40     amount
 41   }
 42 }
 43
 44 // 即使不使用 middleware,你也可以 dispatch action:
 45 store.dispatch(withdrawMoney(100))
 46
 47 // 但是怎样处理异步 action 呢,
 48 // 比如 API 调用,或者是路由跳转?
 49
 50 // 来看一下 thunk。
 51 // Thunk 就是一个返回函数的函数。
 52 // 下面就是一个 thunk。
 53
 54 function makeASandwichWithSecretSauce(forPerson) {
 55
 56   // 控制反转!
 57   // 返回一个接收 `dispatch` 的函数。
 58   // Thunk middleware 知道如何把异步的 thunk action 转为普通 action。
 59
 60   return function (dispatch) {
 61     return fetchSecretSauce().then(
 62       sauce => dispatch(makeASandwich(forPerson, sauce)),
 63       error => dispatch(apologize('The Sandwich Shop', forPerson, error))
 64     )
 65   }
 66 }
 67
 68 // Thunk middleware 可以让我们像 dispatch 普通 action
 69 // 一样 dispatch 异步的 thunk action。
 70
 71 store.dispatch(
 72   makeASandwichWithSecretSauce('Me')
 73 )
 74
 75 // 它甚至负责回传 thunk 被 dispatch 后返回的值,
 76 // 所以可以继续串连 Promise,调用它的 .then() 方法。
 77
 78 store.dispatch(
 79   makeASandwichWithSecretSauce('My wife')
 80 ).then(() => {
 81   console.log('Done!')
 82 })
 83
 84 // 实际上,可以写一个 dispatch 其它 action creator 里
 85 // 普通 action 和异步 action 的 action creator,
 86 // 而且可以使用 Promise 来控制数据流。
 87
 88 function makeSandwichesForEverybody() {
 89   return function (dispatch, getState) {
 90     if (!getState().sandwiches.isShopOpen) {
 91
 92       // 返回 Promise 并不是必须的,但这是一个很好的约定,
 93       // 为了让调用者能够在异步的 dispatch 结果上直接调用 .then() 方法。
 94
 95       return Promise.resolve()
 96     }
 97
 98     // 可以 dispatch 普通 action 对象和其它 thunk,
 99     // 这样我们就可以在一个数据流中组合多个异步 action。
100
101     return dispatch(
102       makeASandwichWithSecretSauce('My Grandma')
103     ).then(() =>
104       Promise.all([
105         dispatch(makeASandwichWithSecretSauce('Me')),
106         dispatch(makeASandwichWithSecretSauce('My wife'))
107       ])
108     ).then(() =>
109       dispatch(makeASandwichWithSecretSauce('Our kids'))
110     ).then(() =>
111       dispatch(getState().myMoney > 42 ?
112         withdrawMoney(42) :
113         apologize('Me', 'The Sandwich Shop')
114       )
115     )
116   }
117 }
118
119 // 这在服务端渲染时很有用,因为我可以等到数据
120 // 准备好后,同步的渲染应用。
121
122 import { renderToString } from 'react-dom/server'
123
124 store.dispatch(
125   makeSandwichesForEverybody()
126 ).then(() =>
127   response.send(renderToString(<MyApp store={store} />))
128 )
129
130 // 也可以在任何导致组件的 props 变化的时刻
131 // dispatch 一个异步 thunk action。
132
133 import { connect } from 'react-redux'
134 import { Component } from 'react'
135
136 class SandwichShop extends Component {
137   componentDidMount() {
138     this.props.dispatch(
139       makeASandwichWithSecretSauce(this.props.forPerson)
140     )
141   }
142
143   componentWillReceiveProps(nextProps) {
144     if (nextProps.forPerson !== this.props.forPerson) {
145       this.props.dispatch(
146         makeASandwichWithSecretSauce(nextProps.forPerson)
147       )
148     }
149   }
150
151   render() {
152     return <p>{this.props.sandwiches.join('mustard')}</p>
153   }
154 }
155
156 export default connect(
157   state => ({
158     sandwiches: state.sandwiches
159   })
160 )(SandwichShop)

View Code

小贴士

  • Middleware 只是包装了 store 的 dispatch 方法。技术上讲,任何 middleware 能做的事情,都可能通过手动包装 dispatch 调用来实现,但是放在同一个地方统一管理会使整个项目的扩展变的容易得多。

  • 如果除了 applyMiddleware,你还用了其它 store enhancer,一定要把 applyMiddleware 放到组合链的前面,因为 middleware 可能会包含异步操作。比如,它应该在 redux-devtools 前面,否则 DevTools 就看不到 Promise middleware 里 dispatch 的 action 了。

  • 如果你想有条件地使用 middleware,记住只 import 需要的部分:

1 let middleware = [ a, b ]
2 if (process.env.NODE_ENV !== 'production') {
3   let c = require('some-debug-middleware')
4   let d = require('another-debug-middleware')
5   middleware = [ ...middleware, c, d ]
6 }
7 const createStoreWithMiddleware = applyMiddleware(...middleware)(createStore)

View Code

  • 这样做有利于打包时去掉不需要的模块,减小打包文件大小。

  • 有想过 applyMiddleware 本质是什么吗?它肯定是比 middleware 还强大的扩展机制。实际上,applyMiddleware 只是被称为 Redux 最强大的扩展机制的 store enhancers 中的一个范例而已。你不太可能需要实现自己的 store enhancer。另一个 store enhancer 示例是 redux-devtools。Middleware 并没有 store enhancer 强大,但开发起来却是更容易的。

  • Middleware 听起来比实际难一些。真正理解 middleware 的唯一办法是了解现有的 middleware 是如何工作的,并尝试自己实现。需要的功能可能错综复杂,但是你会发现大部分 middleware 实际上很小,只有 10 行左右,是通过对它们的组合使用来达到最终的目的。

转载于:https://www.cnblogs.com/ZSG-DoBestMe/p/5280171.html

Redux API之applyMiddleware相关推荐

  1. 关于Redux的一些总结(一):Action 中间件 异步

    在浅说Flux开发中,简单介绍了Flux及其开发方式.Flux可以说是一个框架,其有本身的 Dispatcher 接口供开发者:也可以说是一种数据流单向控制的架构设计,围绕单向数据流的核心,其定义了一 ...

  2. 从源码理解Redux和Koa2的中间件机制

    Redux和Koa的中间件机制相关源码都很精简. 正文我将直接引用部分源码,并加以注释来帮助我们更清晰的理解中间件机制. Reudx redux的中间件机制在源码中主要涉及两个模块 内部的compos ...

  3. Redux 进阶 - react 全家桶学习笔记(二)

    注:这篇是17年1月的文章,搬运自本人 blog... https://github.com/BuptStEve/... 零.前言 在上一篇中介绍了 Redux 的各项基础 api.接着一步一步地介绍 ...

  4. 使用 Redux 和 Axios 获取数据

    正如许多开发人员所知,状态管理是您在构建健壮的应用程序时必须处理的众多问题之一.它会很快变成一场噩梦,尤其是在客户端. Redux 强制执行单向数据流,这使得理解事件如何改变应用程序状态变得容易.伟大 ...

  5. React Redux 与胖虎他妈

    本文将涉及以下三块内容: 多 Reducer 中间件 封装组件方便获取 Store 前言 在上一篇文章<React Redux与胖虎> 中我们详尽地介绍了 React Redux,也写了一 ...

  6. koa/redux middleware 深入解析

    middleware 对于现有的一些框架比如koa,express,redux,都需要对数据流进行一些处理,比如koa,express的请求数据处理,包括json.stringify,logger,或 ...

  7. 使用React,Redux,redux-sage构建图片库(翻译)

    看到这篇文章build an image gallery using redux saga,觉得写的不错,长短也适中. 文后有注释版的github代码库,请使用comment分枝. Flickr AP ...

  8. 简单、好懂的 Redux middleware 原理

    It provides a third-party extension point between dispatching an action, and the moment it reaches t ...

  9. redux VS mobx (装饰器配合使用)

    前言:redux和mobx都是状态管理器,避免父级到子级再到子子级嵌套单向数据流,可以逻辑清晰的管理更新共享数据.(刷新页面redux储蓄数据即消失) 配置使用装饰器(使用高阶函数包装你的组件): n ...

最新文章

  1. 基于AgileEAS.NET SOA 平台SAAS架构技术的开源分销ERP系统-SmartERP.NET下载配置说明
  2. STM32 基础系列教程 35 - Lwip_sntp
  3. mysql 代替intersect_mysql替代INTERSECT
  4. 转载 从SRAM中读写一个数据问题——Verilog
  5. [vue] 你认为vue的核心是什么?
  6. 通过例子理解事务的4种隔离级别
  7. 1.12 改善你的模型的表现
  8. 关于直播带货被坑的厂商
  9. In addition, Clem also revealed that they have
  10. 生信SCi好用的画图软件
  11. Microsoft SQL Server 2000的版本区别及选择
  12. maven Web项目中POM的配置信息
  13. 主板启动提示USB设备出现电涌,15秒后关闭以保护系统问题
  14. 网页html5播放器,一个强大的开源HTML5视频播放器,字节出品
  15. 使用MobaXterm的ssh登录阿里云服务器总是acess deind
  16. 校招宣传片的制作思路
  17. Python 结合Ansible 把管理资产信息自动插入到CMDB中
  18. 测试人高中低音的软件,【精】Q3原车音箱35TFS调试测试与高中低音设置,放音乐调试结果附最后...
  19. set 和 dict
  20. 开源系统-ERP企业资源管理系统

热门文章

  1. 华为NOVa8Pr0是用鸿蒙系统吗,华为Nova8即将发布,采用麒麟芯片,高端平板适配鸿蒙系统...
  2. apache ajax 跨域访问,Apache 实现AJAX跨域请求
  3. Jmeter BeanShell学习(一) - BeanShell取样器(一)
  4. 矩形波傅里叶变换对以及三角波傅里叶变换
  5. java jar包示例_Java包getImplementationTitle()方法和示例
  6. 根据F12在页面中调整div的大小
  7. 466. 统计重复个数 golang[转]
  8. Eclipse : Unresolved inclusion
  9. C++11中的右值引用
  10. 数据结构--顺序栈和链式栈