浅谈Redux中间件的实践
最近项目前端开发框架采用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项目中可以多加实践。
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Vue与Node.js通过socket.io通信的示例
#一、Node中socket.io基础 1、是什么 Socket.IO类库,是在服务器和浏览器之间提供一个共享接口,其可以用于实现以下几种通信方式: HTML5中的WebSocket通信 Flash中使用的WebSocket通信 XHR轮询 JSONP轮询 Forever Iframe 在通信时,客户端与服务器端可以使用相同的API 2、怎么用 原理:创建Scoket.IO服务器,该服务器依赖于一个已经创建的HTTP服务器 服务器端引入 var http=require('http') var sio=require('socket.io') var server=http.createServer((req,res)=>{ res.writeHead(200,{'Content-type':'text/html'}) res.end(fs.readFileSync('./snak.html')) }).listen(8088)//创thhp建服务器 var socket=sio.listen(server)//监听http服务器 socket.on('connection',(...
- 下一篇
前端杂谈: CSS 权重 (Specificity)
前端杂谈: CSS 权重 (Specificity) css 权重想必大家都听说过, 一些简单的规则大部分人也都知道: 较长的 css selector 权重会大于较短的 css selector id selector 权重高于 class selector. 但是具体规范是什么? 浏览器是按照什么标准来判定不同选择器的权重的呢? 让我们来看一下官方文档是怎么说的~ 第一个关键词: Specificity Specificity is the means by which browsers decide which CSS property values are the most relevant to an element and, therefore, will be applied. Specificity is based on the matching rules which are composed of different sorts of CSS selectors 官方文档中用 Specificity: 特异性 来表示一个 css selector 和其元素的相关性...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- Linux系统CentOS6、CentOS7手动修改IP地址
- Docker安装Oracle12C,快速搭建Oracle学习环境
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- CentOS6,CentOS7官方镜像安装Oracle11G
- CentOS7安装Docker,走上虚拟化容器引擎之路
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- 设置Eclipse缩进为4个空格,增强代码规范
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- 2048小游戏-低调大师作品