Redux API之applyMiddleware

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/396638.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机2018创业方向,推荐2018年创业的方向

原标题&#xff1a;推荐2018年创业的方向1 新电商传统的零售业收到互联网电商的重冲击&#xff0c;从而进行线上线下的结合是必然的趋势&#xff0c;新零售&#xff0c;新电商&#xff0c;是几千万零售企业成功转型的必然之路&#xff0c;学习一套全面的新电商转型的方法&#…

包无法安装_详细教程 | 安装Python编程环境以及使用OpenpyXl操作Excel

详细教程 | 安装Python编程环境以及使用OpenpyXl操作Excel注意&#xff1a;下列教程为 Windows7 64位&#xff1b;Windows 10有部分步骤有差异&#xff0c;请参考使用&#xff01;01 下载Python程序安装包首先前往Python官网 www.python.org,进入官网点击 Downloads,然后点击 W…

request重定向_golang不想http自动处理重定向的解决方案

前言有时候发送http请求不想让库自动帮忙处理重定向&#xff0c;库里面默认的是会把所有重定向都完成一遍&#xff0c;结果就是最后一个没有重定向的请求的结果。因此需要一种方案直接获取首次访问的结果&#xff0c;不走重定向。go的http库里面是使用如下代码检查重定向的&…

float foo=42e1为什么错_为什么重写了equals()也要重写hashCode()

小Hub领读&#xff1a;虽然是很基础的一篇文章&#xff0c;但是对于equals、hashcode两个方法&#xff0c;相信很多人都与其中的规则不熟悉&#xff0c;来跟着小Hub花个8分钟回顾一下&#xff01;作者&#xff1a;不学无数的程序员https://my.oschina.net/u/4030990/blog/31341…

ssh客户端_一款基于TAS框架的SSH客户端蠕虫

TEA是一款基于TAS框架的SSH客户端蠕虫&#xff0c;从本质上说&#xff0c;它是一个仿冒的SSH客户端&#xff0c;它能够修改tty输入/输出来实现任意命令执行&#xff0c;或通过SSH连接来上传自身以实现渗透感染。为了实现该工具的正常功能&#xff0c;远程主机需要满足以下条件&…

分享到系统面板_win7电脑没有nvidia控制面板怎么办【解决方法】

我们在使用电脑的时候&#xff0c;当电脑显卡出现问题导致屏幕画面不清晰时&#xff0c;可以使用win7系统自带nvidia控制面板&#xff0c;它能够对显卡进行设置&#xff0c;提升显卡功能&#xff0c;不过很多电脑用户点击nvidia控制面板时却提示nvidia显示设置不可用&#xff0…

day3-文件操作之基本操作

一、文件的基本操作 文件内容&#xff1a; Somehow, it seems the love I knew was always the most destructive kind 不知为何&#xff0c;我经历的爱情总是最具毁灭性的的那种 Yesterday when I was young 昨日当我年少轻狂1、read() 当read()函数中传入整数(int)参数&#…

spad 探测器_从光到光子—“单光子”探测器

光电探测器光电探测器是指在光辐射作用下将其非传导电荷变为传导电荷的一类器件。在电子学中&#xff0c;二极管是一种具有不对称传输特性的双端电子元件&#xff0c;在一个方向上对电流具有低(理想为零)电阻&#xff0c;在另一个方向上具有高(理想为无限)电阻。最常见的类型如…

天地图专题五:在天地图上绘制电子区域并保存数据

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请注明出处。 上一文章讲了如何在天地图上显示坐标轨迹。 本文介绍如何在天地图上绘制电子区域&#xff08;电子范围或电子栅栏&#xff09;&#xff0c;并且&#xff0c;我们要将我们绘制的电子区域的坐标数据保存到数…

微信和支付宝的服务器在哪里,手机恢复出厂设置,里面支付宝与微信怎么办?原来数据在这里...

当手机使用一段时间之后&#xff0c;因为硬件落后会出现卡顿、内存不足等情况&#xff0c;这个时候提高手机速度最直接的一个办法就是恢复出厂设置&#xff0c;虽然不能从根源上解决问题&#xff0c;但是还是可以凑合个半年时间的。那么这个时候就出现一个问题&#xff0c;手机…

mysql insert 不需要日志_MySQL数据库性能优化(1)「转」

1、MySQL概述从本文开始我们将讨论建立在块存储方案之上的关系型数据库的性能优化方案和集群方案。关系型数据库的选型将以创业公司、互联网行业使用最广泛的MySQL数据为目标&#xff0c;但是MySQL的安装过程和基本使用方法等知识并不在我们讨论的范围内。后续几篇文章我们首先…

Java swing中的keyListener使用事例

最近在学习Java swing&#xff0c;写了一个域内聊天室&#xff0c;实现用户登录ip,端口号之后&#xff0c;进入聊天窗口聊天&#xff1a; 通过菜单条增加了几个功能&#xff0c;边框&#xff0c;字体&#xff0c;颜色和文件传输。风格里的样式都可以通过自己选择来设置。 介绍以…

「前端」History API与浏览器历史堆栈管理

本文由尚妆前端开发工程师欲休撰写 本文发表于尚妆博客&#xff0c;欢迎订阅&#xff01; 移动端开发在某些场景中有着特殊需求&#xff0c;如为了提高用户体验和加快响应速度&#xff0c;常常在部分工程采用SPA架构。传统的单页应用基于url的hash值进行路由&#xff0c;这种实…

Andrew Ng机器学习(一):线性回归

1.什么是线性回归&#xff1f; 用线性关系去拟合输入和输出。 设输入为x&#xff0c;则输出yaxb。 对于多元的情况yb1a1x1a2x2...anxn。 用θ表示系数&#xff0c;可以写作&#xff1a; 其中&#xff0c;x01。 2.线性回归有什么用&#xff1f; 对于连续输入和输出的问题&#x…

ICMP(Internet Control Message Protocol)网际控制报文协议初识

ICMP是&#xff08;Internet Control Message Protocol&#xff09;Internet控制报文协议。它是TCP/IP协议族的一个子协议&#xff0c;用于在IP主机、路由器之间传递控制消息。控制消息是指网络通不通、主机是否可达、路由是否可用等网络本身的消息。这些控制消息虽然并不传输用…

oracle 删除主键_大数据量删除的思考 4

译者 汤健 沃趣科技数据库技术专家出品 沃趣科技在本系列的前一期文章中&#xff0c;我制作了一些图&#xff0c;突出显示了按表扫描执行大量删除操作和按索引范围扫描执行大量删除之间的主要区别。根据所涉及的数据模式&#xff0c;选择正确的策略可能对随机I/Os的数量、生…

redis 持久化 + 主从复制+ 集群

2019独角兽企业重金招聘Python工程师标准>>> 一、 Linux 下的 Redis 安装 && 启动 && 关闭 && 卸载 http://blog.csdn.net/zgf19930504/article/details/51850594 注&#xff1a;设置 redis.conf bind***.***.*.(127.0.0.1) redis启动&…

怎么运行c语言_C语言 原来是这样调用硬件的

大家都知道我们可以使用C语言写一段程序来控制硬件工作&#xff0c;但你知道其工作原理吗&#xff1f;网友北极C语言在实际运行中&#xff0c;都是以汇编指令的方式运行的&#xff0c;由编译器把C语言编译成汇编指令&#xff0c;CPU直接执行汇编指令。所以这个问题就变成&#…

更新和插入的并发问题_mysql经典面试题:如何读写分离?主从原理是啥?同步的延时问题...

面试题你有没有做 MySQL 读写分离&#xff1f;如何实现 MySQL 的读写分离&#xff1f;MySQL 主从复制原理的是啥&#xff1f;如何解决 MySQL 主从同步的延时问题&#xff1f;考点分析高并发这个阶段&#xff0c;肯定是需要做读写分离的&#xff0c;啥意思&#xff1f;因为实际上…

maven建立webapp项目时显示Cannot change version of project facet Dynamic web module to 2.5

为什么80%的码农都做不了架构师&#xff1f;>>> 网上查了很多东西都没啥用&#xff0c;其实直接把这段代码加到web.xml头部&#xff0c;自然就不报错了 <?xml version"1.0" encoding"UTF-8"?> <web-app xmlns:xsi"http://www.…