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…

Activity、Fragment、Dialog基类简单整理

版权声明&#xff1a;本文为HaiyuKing原创文章&#xff0c;转载请注明出处&#xff01; 概述 这里简单记录下Activity、Fragment、Dialog基类中的常规写法&#xff0c;后续根据项目需求进行相应的扩展。 BaseActivity.java package com.why.project.myapptemplet.activity;impo…

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

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

C语言项目开发-项目架构和编程命名规范

一个项目的流程&#xff1a;1、公司市场人员与客户交流&#xff0c;了解客户、引导客户使用公司最优资源并产出一份市场需求文档 2、公司需求人员&#xff08;BA&#xff09;与客户交流&#xff0c;了解客户需求并产出一个软件需求文档 3、项目经理、开发小组成员、需求人员&am…

ajax登录验证的原理,ajax用户登录验证-get和post提交方式,与工作原理—2018-8-15...

ajax用户登录验证&#xff1a;实例html>Ajax实战:表单验证用户登录邮箱: 密码: 提交let btn document.getElementsByTagName(button)[0];btn.onclick function () {//1.创建xhr对象let xhr new XMLHttpRequest();//2.监听响应状态xhr.onreadystatechange function(){// …

将Python脚本打包成可执行文件

Python是一个脚本语言&#xff0c;被解释器解释执行。它的发布方式&#xff1a; .py文件&#xff1a;对于开源项目或者源码没那么重要的&#xff0c;直接提供源码&#xff0c;需要使用者自行安装Python并且安装依赖的各种库。&#xff08;Python官方的各种安装包就是这样做的&a…

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;远程主机需要满足以下条件&…

Selenium入门11 滚动条控制(通过js)

这一节要有js基础。做web端的UI自动化必须要有html&#xff0c;css&#xff0c;javascript前端基础。 滚动条控制&#xff1a; 1 移动垂直滚动条 document.documentElement.scrollTop 2 移动垂直滚动条 document.documentElement.scrollLeft 3 找到某个元素&#xff0c;移动到可…

Qt之QNetworkInterface

简述 QNetworkInterface类负责提供主机的IP地址和网络接口的列表。 QNetworkInterface表示了当前程序正在运行时与主机绑定的一个网络接口。每个网络接口可能包含0个或多个IP地址&#xff0c;每个IP地址都可选择性地与一个子网掩码和/或一个广播地址相关联。这样的列表可以通过…

第二周计划

上周计划回顾 3.5 ~ 3.11 数据&#xff1a; 评师网爬取&#xff0c;完成&#xff1a;2k条记录 finished后端 数据结构 技术选型 学校API封装未完成&#xff1a;后端负责人出差 工作暂停产品 功能设计&#xff1a;主要功能提交&#xff1a;原型图 几个页面 每个页面大概功能完成…

python编程软件排行榜_PYPL 9月编程语言排行榜发布 Python一枝独秀

开发者可以将 PYPL 作为一个参考&#xff0c;决定学习何种语言或 IDE&#xff0c;或者在新的软件项目中使用何种语言或数据库。9 月份的榜单如下&#xff1a;前五名分别是 Python、Java、JavaScript、C# 与 PHP。相比去年 9 月份的数据&#xff0c;除了 Python 大幅上涨了 4.5%…

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

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

Python之数据加密与解密(hashlib、hmac、random、base64、pycrypto)--转载

本文内容 数据加密概述Python中实现数据加密的模块简介hashlib与hmac模块介绍random与secrets模块介绍base64模块介绍pycrypto模块介绍总结参考文档提示&#xff1a; Python 2.7中的str是字节串&#xff0c;而Python 3.x中的str是字符串。本文中的代码都是通过Python 2.7实现的…

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)参数&#…

QT连接多种数据库f方法及测试

QT提供了对多种数据库的访问支持&#xff0c;对SQL Server也可以通过ODBC来进行访问。要想顺利访问SQL Server。 首先要保证以下几点&#xff1a;1. QT编译时已经编译了QtSql2. 编译了ODBC插件。可以通过 configure -plugin-sql-odbc来保证&#xff0c;也可以单独编译~/src/plu…

服务器如何实现电脑无线桥接,无线路由器WDS桥接成功副路由器下电脑无法上网怎么办【解决方法】...

摘 要无线WDS桥接设置完成后&#xff0c;在副路由器管理面&#xff0c;运行状态 无线状态 中&#xff0c;WDS状态显示成功&#xff0c;但电脑通过副路由无法上网。该问题可能与主、副路由器的设置有关&#xff0c;如下图所示&#xff1a; 解决办法&#xff1a; 排查一&#xff…

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

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

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

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