浅谈Redux中间件的实践

西域战神 2018-11-20 15:30:14 ⋅ 613 阅读

作者:peakedness丶 

原文地址:https://my.oschina.net/u/3970421/blog/2878039

最近项目前端开发框架采用React+Redux进行实现,但是,如何异步访问服务器端,以及想要在开发过程中进行状态树日志的输出,所以怎么才能解决这两个问题? 采用Redux中间件

为什么要使用中间件

在利用Redux进行状态管理时,用户在UI层面触发行为,一个action对象通过store.dispatch派发到Reducer进行触发,接下来Reducer会根据type来更新对应的Store上的状态树,更改后的state会触发对应组件的重新渲染。如下图所示。在这个流程中,action对象是一个同步的对象,是一个包含type字段的简单对象,但是在访问服务器时,由于浏览器是单线程的,不会一遍渲染组件一遍等待服务器返回的结果,因此我们需要设计一种异步访问服务器的方法来实现与服务器端的正常通信。 

中间件介绍

在Redux架构下,一个action对象在通过store.dispatch派发,在调用reducer函数前,会先经过一个中间件环节,如下图所示。

 从上图可以看出,在一个Redux架构中可以用多个中间件,这些中间件一起组织处理请求的“管道”。一个中间件是一个独立的函数,可以组合使用,中间件有一个统一的接口,正因为一个中间件只能完成一个特定的功能,所以把多个中间件组合在一起才能满足比较丰富的应用需求。当然在使用时,也需要按照顺序依次处理传入的action,只有排在前面的中间件完成任务之后,后面的中间件才能有机会继续处理action。 

中间件的特点

  • 中间件是独立的函数

  • 中间件可以组合使用

  • 中间件有一个统一的接口

中间件接口

每个中间件必须定义为一个函数,返回一个接受next参数的函数,而这个接受next参数的函数又返回一个接受action参数的函数。next参数本身也是一个函数,中间件调用这个next函数通知Redux自己的处理工作已经结束。

一个什么都不做的中间件代码如下:

function doNothingMiddleware({dispatch, getState}) {  
return function(next){  
   return function(action){    
       return next(action);    }
       //前端全栈学习交流圈:866109386  }
//面向1-3年经验前端人员}//帮助突破技术瓶颈,提升思维能力

包含的功能有:

  • 调用dispatch派发出一个新的action对象

  • 调用getState获得当前Redux Store上的状态

  • 调用next告诉Redux当前中间件工作完毕,让Redux调用下一个中间件

  • 访问action对象action上的所有数据

在一个Redux应用如果想要使用中间件,必须通过applyMiddleware来生成。Redux的源码文件非常简单,由五个文件一起组成,分别是createStore.js,applyMiddlware.js,compose.js,bindActionCreator.js,combineReducers.js。与createStore是用来创建一个状态树,并且暴露出几个方法,包括dispatch,subscribe,getState,replaceReducer和$$observable,给createStore传入的参数有reducer,preloadedState和enhancer,其中enhancer就是一个store增强器,是一个函数,只能用applyMiddleware生成。applyMiddleware函数是根据外部函数(中间件函数)包装原来的dispatch函数,然后将新的dispatch函数暴露出去。

//根据外部函数(中间件函数)包装原来的dispatch函数,然后将新的dispatch函数暴露了出去

export default function applyMiddleware(...middlewares) {
//return一个函数,它可以接受createStore方法作为参数,给返回的store的dispatch方法再进行一次包装 return createStore => (...args) => {
//agrs包含reducer, preloadedState, enhancer  const store = createStore(...args)  
let dispatch = () => {  
throw new Error(    `Dispatching while constructing your middleware is not allowed. ` +     `Other middleware would not be applied to this dispatch.`   )  }  //暴露两个方法给外部函数  const middlewareAPI = {  
getState: store.getState,  
dispatch: (...args) => dispatch(...args)  }  
//传入middlewareAPI参数并执行每一个外部函数,返回结果汇聚成数组  const chain = middlewares.map(middleware => middleware(middlewareAPI))  
//这里用到了compose方法  dispatch = compose(...chain)(store.dispatch)  return {   ...store,   dispatch  }
//前端全栈学习交流圈:866109386 }
//面向1-3年经验前端人员}//帮助突破技术瓶颈,提升思维能力

中间件与增强器的区别

中间件和增强器都是对Redux Store的增强,但是中间件仅仅是对Redux Store的dispatch方法进行了增强,也就是从dispatch函数调用到action对象被reducer处理这个过程中的操作,增强器是对Redux Store进行更深层次的增强定制,需要使用Store Enhancer,通过阅读增强器接口,一个增强器其实利用随给的参数创造出一个store对象,然后定制对象,最后把Store对象返回。总的对比如下:

  • 中间件: 可以用来增强redux store的dispatch函数,也就是从dispatch函数调用到action对象被reducer处理这个过程中的操作

  • 增强器: 对redux store进行更深层次的增强定制,可以增强redux store的各个方面。

异步访问服务器:

异步action对象

在没有引入中间件时,社会治理子系统在开发时,所有的action都是同步的,一个同步的action对象是一个包含type字段的简单对象,但是我们需要实现一个异步action对象,是一个函数,在action触发之后,在reducer接收到执行命令之前可以进行一个异步操作。 我们引入redux-thunk来实现异步访问服务器方法,一个访问服务器的action,至少要涉及三个action类型:

  • 表示异步操作已经开始的action类型;

  • 表示异步操作成功的action类型;

  • 表示异步操作失败的action类型;

Redux-thunk源代码解析

Redux-thunk中间件是Redux中异步操作的解决方法之一,在action对象被reducer函数处理之前,是插入异步功能的时机,代码非常简单:

function create ThunkMiddleware(extraArgument){  
return ({dispatch, getState}) => next => action => {    
if(typeof action === ‘function'){    
   return action(dispatch, getState, extraArgument);   }  
   return next(action)  } }
const thunk = createThunkMiddleware();
export default thunk;

createThunkMiddleware函数返回了一个函数,是实际处理每个action对象的函数,首先检查参数action的类型,如果是函数类型的话,就执行这个action函数,把dispatch和getState 作为参数传递出去,否则就调用next让下一个中间件继续处理action。

Redux-thunk的使用:

首先,安装redux-thunk,在已经安装了node.js的命令窗口中运行 “npm install redux-thunk --save-dev”,在store.js中引入redux-thunk,并且确保redux的applyMiddleware函数也引入。具体实现代码如下。

import {createStore, combineReducers, applyMiddleware} from ‘redux'; import {otherState, dataState} from ‘reducers';
import thunkMiddleware from ‘redux-thunk'; var reducers = combineReducers({  otherState,  dataState }); var store = createStore(reducers, applyMiddleware(thunkMiddleware)); export default store;

在成功引入了redux-thunk后,我们也要设计异步操作的action对象,例如,在设备管理模块中,成功保存设备信息后要重新获取设备信息,代码如下:

function saveInfo(params){  
let url = “/api/device”;  
return function(dispatch, getState){    dispatch(saveInfoRequest());    
return Http.get(url, {      
params: params    }).then(res=>{      
if(res && res.type === 0){        dispatch(saveInfoSuccess ());        
let dataState = getState().dataState;        
let newParams = {          
   start: dataState.start,          
   limit: dataState.limit,          
   searchName: dataState.searchName        };        dispatch(getInfo(newParams))      }    }).catch(error=>{       dispatch(saveInfoFailure (error));    });  } }

从这个saveDeviceInfo返回的函数中,不仅可以dispatch一个同步的action对象,还可派发另一个异步action对象,来满足一些有着先后关系的业务逻辑,代码可读性要比用Promise实现起来代码更加清晰。

Redux-logger使用

在开发阶段,我们需要对redux数据流中每个流程进行监控,需要log输出,redux-logger是官方推荐的一款日志中间件,使用起来非常方便。当然,要使redux-logger生效,需要保证在系统中使用redux进行状态管理,否则没有任何日志输出。 Redux-logger的使用方法可以分为两种,基本使用方法如下:

import { applyMiddleware, createStore} from ‘redux'; import logger from ‘reudx-logger'
const store = createStore(  Reducer,  applyMiddleware(logger) )

也可以自己写一个日志输出中间件,代码如下:

var logger = store => next => action => {  
console.log('[action]', action)  
console.log(`[action] type:${action.type} payload:${JSON.stringify(action.payload)}`)  next(action)  
console.log('[store]', store.getState())  
console.log(`[store] ${JSON.stringify(store.getState())}`) }

总结

Redux中间件可以增强Store.dispatch方法,多个中间件可以组成“管道”,按照顺序去处理action对象,在依次处理过后,才会有机会被reducer处理。中间件的应用场景很多,除了可以支持异步访问服务器,还有许多很好的中间件插件,例如react-addons-perf进行调试,和redux-logger来记录状态,也可以根据业务需求来自己编写中间件,应用非常灵活,在其他react项目中可以多加实践。

---------------END----------------

后续的内容同样精彩

长按关注“IT实战联盟”哦



全部评论: 0

    我有话说:

    http中Cache-Control

    前言   我们用http访问时,会先发送一个请求,之后服务器返回一个应答,在Chrome开发者工具(按F12或右击选择检查)中展现了整个过程:     第一部分

    Node实战篇:Express中间与request(四)

    Express 是一个路由和中间 Web 框架,其自身只具有最低程度功能:Express 应用程序基本上是一系列中间函数调用。

    Node实战篇:Express 中间 cookie-parser(六)

    cookieParser()实际上是对http传入cookie进行解析后赋值给req.cookies,使得中间可用

    Node实战篇:Express 中间-body-parser(五)

    body-parser是什么?body-parser是一个HTTP请求体解析中间,使用这个模块可以解析JS

    「推荐」通过API网关实现微服务管控-限流,熔断和降级

      今天准备下基于API网关来实现微服务治理管控中服务限流,熔断和降级方面内容。在前面微服务架构时候也到过类似通过Hystrix,Sentinel来是服务限流熔断。包括也不断

    Kafka 慌了!这个中间,要火了?

    你知道吗?在消息中间编年史上,RocketMQ可谓独当一面。作为Apache 顶级项目(TLP),Apache RocketMQ 是国内首个非 Hadoop 生态体系顶级项目,开源至今被全球

    「开源资讯」陌陌安全团队开源Java静态代码审计插

    陌陌安全本次开源Java静态代码安全审计插,侧重于在编码过程中发现项目潜在安全风险,并提供一键修复能力。 此插作为Java项目静态代码安全审计工具,侧重于在编码过程中发现项目潜在安全风险

    京东技术:如何实现百万TPS?详解JMQ4存储设计

    JMQ是京东中间团队自研消息中间,诞生于2014年,服务京东近万个应用,2018年11.11大促期间峰值流量超过5000亿条消息

    「转载」蘑菇街消息系统上云实践

    小编又来啦~本周要推荐给大家是一篇跟中间上云相关技术文章,这里面详细记录了,蘑菇街自研消息系统上云全过程,也是市面上开放出来为数不多企业自研组件上云实践。有相关需求同学可以好好学习下

    「开源资讯」任务调度中间PowerJob 3.3.0 发布

    PowerJob简介 PowerJob是全新一代分布式调度与计算框架,能让您轻松完成作业调度与繁杂任务分布式计算。 下载地址:https://gitee.com/KFCFans/PowerJob

    PowerJob v3.3.2 已经发布,分布式任务调度中间

    PowerJob v3.3.2 已经发布,PowerJob 是全新一代分布式调度与计算框架,能让您轻松完成作业调度与繁杂任务分布式计算。 此版本更新内容包括: Features 支持控制台查看

    Knife4j 2.0.8 发布,轻量级微服务聚合文档中间诞生

    Knife4j前身是swagger-bootstrap-ui,是一个为Swagger接口文档赋能工具 文档:https://xiaoym.gitee.io/knife4j/ 效果(旧版):http

    京东技术:开发属于自己 | IDEA & Android Studio插开发指南

    是否曾经被ide重复繁琐操作所困扰,又或者没有心仪UI控而难受。那么请阅读这篇文章,掌握idea插开发流程,开发属于自己,造福开源社区。

    微信小程序微商城(九):微信授权并实现个人中心页面页面

    实现微商城微信授权并获取用户信息和个人中心页面布局

    架构实战篇:一个可供中小团队参考微服务架构技术栈

    作者近年一直在一线互联网公司(携程,拍拍贷等)开展微服务架构实践,根据我个人一线实践经验和我平时对Spring Cloud调研,我认为Spring Cloud技术栈中有些组件离生产级开发尚有

    阿里大牛垃圾回收算法是如何设计

    前言 如果大家关注 JDK,会发现在频繁发布 JDK 版本中,和垃圾回收相关 JEP (JDK Enhancement Proposals,Java 增强提案)越来越多了,垃圾回收

    Martian-cloud 4.0,跟注册中心拜拜了,基于传染机制分布式组件诞生

    这次真要跟注册中心讲拜拜了,微服务不再需要占用一套注册中心集群了,大大节约了运维成本 更新点如下 丢弃了一开始【生产者->注册中心->消费者】模型 采用传染机制,实现服务发现与