redux-applyMiddleware实现理解+自定义中间件
前言:
终于好好理解了middleware。。。。
1.redux middleware提供的是位于 action 被发起之后,到达 reducer 之前的扩展点。
redux通过store.dispatch(atcion),发起一个action给store,store接收后把当前state与action一起传给reducer,所以middleware做文章的地方就是dispatch,在原生的dispatch执行之前,先进行一些列的操作。
实现middleware的方法:下面以logger中间件为例
1.手动记录(不可能会使用这种的吧)
let action = addTodo('Use Redux')
console.log('dispatching', action)
store.dispatch(action)
console.log('next state', store.getState())
2.封装dispatch,
要发起action的时候,不用 dispatch 而是用 disptchAddLog()。(把这个方法放在store里面、好像还不错的样子)
function dispatchAndLog(store, action) {
console.log('dispatching', action)
store.dispatch(action)
console.log('next state', store.getState())
}
3.猴子补丁,
通过重写store.dispatch(), (重写之后,所使用的dispatch(), 已经不是原生的dispatch了,使用多个中间件,就是不断改写前一次生成的dispatch),
(注意:原生的dispatch,已经不可能找到,也就是不能单独使用原始dispatch了)
function(store) {
let next = store.dispatch
store.dispatch = function dispatchAndLog(action) {
console.log('dispatching', action)
let result = next(action)
console.log('next state', store.getState())
return result
}
}
4.隐藏猴子补丁,
乍一看好像和猴子补丁没什么却别,但其实它把赋值的给store.dispatch的逻辑放到了中间件函数的外面,需要外面提过一个applyMiddleware辅助函数来完成插值,除此之外,真的没什么区别。(原理还是猴子补丁)
function logger(store) {
let next = store.dispatch
// 我们之前的做法:
// store.dispatch = function dispatchAndLog(action) {
return function dispatchAndLog(action) {
console.log('dispatching', action)
let result = next(action)
console.log('next state', store.getState())
return result
}
}
多个中间件 的实现方式:
function applyMiddlewareByMonkeypatching(store, middlewares) {
middlewares = middlewares.slice()
middlewares.reverse()
// 在每一个 middleware 中变换 dispatch 方法。
middlewares.forEach(middleware =>
store.dispatch = middleware(store)
)
}
5.移除猴子补丁,
相对隐藏猴子不同,把middleware函数里面 let next = store.dispatch ,放到函数外面 dispatch = middleware(store)(dispatch)
function logger(store) {
return function wrapDispatchToAddLogging(next) {
return function dispatchAndLog(action) {
console.log('dispatching', action)
let result = next(action)
console.log('next state', store.getState())
return result
}
}
}
看一下多个中间件实现方式你就知道了,
是否发现:在 return 的 assign 之前, store.dispatch 都是原生的,并没有被改变。所以中间件里面是否可以使用store.dispatch调用原生的,(如果有需要的话),然而笔者试着调用了一下,并不行,会不断的触发,就是已经是该改变之后的了。
// 警告:这只是一种“单纯”的实现方式!
// 这 *并不是* Redux 的 API. function applyMiddleware(store, middlewares) {
middlewares = middlewares.slice()
middlewares.reverse() let dispatch = store.dispatch
middlewares.forEach(middleware =>
dispatch = middleware(store)(dispatch)
) return Object.assign({}, store, { dispatch })
}
logger中间件换成es6的箭头函数更好看
const logger = store => next => action => {
console.log('dispatching', action)
let result = next(action)
console.log('next state', store.getState())
return result
}
6.redux中是现实方法
这与 Redux 中 applyMiddleware() 的实现已经很接近了,但是有三个重要的不同之处:
它只暴露一个 store API 的子集给 middleware:
dispatch(action)和getState()。它用了一个非常巧妙的方式来保证你的 middleware 调用的是
store.dispatch(action)而不是next(action),从而使这个 action 会在包括当前 middleware 在内的整个 middleware 链中被正确的传递。这对异步的 middleware 非常有用。为了保证你只能应用 middleware 一次,它作用在
createStore()上而不是store本身。因此它的签名不是(store, middlewares) => store, 而是(...middlewares) => (createStore) => createStore。
总结:
redux提供了applyMiddleware(), 如果我们自定义中间件,也就变的很简单了
function myMiddleware = (store) => (next) => (action) => {
console.log('进入了我自己定义的中间件');
let result = next(action); // 执行下一步
// let result = store.dispatch(action); //不调用next,直接使用store.dispatch调用原生。然后是不行的,会陷入dispatch死循环。
return result;
}
applyMiddleware会帮我们执行前面两层函数。myMiddleware(store)(dispatch)
redux-thunk的实现也是很牛掰
function createThunkMiddleware(extraArgument) {
return ({ dispatch, getState }) => next => action => {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
};
}
const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;
export default thunk;
redux-applyMiddleware实现理解+自定义中间件的更多相关文章
- redux middleware 的理解
前言 这几天看了redux middleware的运用与实现原理,写了一个百度搜索的demo,实现了类似redux-thunk和redux-logger中间件的功能. 项目地址:https://git ...
- redux:applyMiddleware源码解读
前言: 笔者之前也有一篇关于applyMiddleware的总结.是applyMiddleware的浅析. 现在阅读了一下redux的源码.下面说说我的理解. 概要源码: step 1: apply ...
- ASP.NET Core 1.1 静态文件、路由、自定义中间件、身份验证简介
概述 之前写过一篇关于<ASP.NET Core 1.0 静态文件.路由.自定义中间件.身份验证简介>的文章,主要介绍了ASP.NET Core中StaticFile.Middleware ...
- ASP.NET Core 1.0 静态文件、路由、自定义中间件、身份验证简介
概述 ASP.NET Core 1.0是ASP.NET的一个重要的重新设计. 例如,在ASP.NET Core中,使用Middleware编写请求管道. ASP.NET Core中间件对HttpCon ...
- asp.net core中写入自定义中间件
首先要明确什么是中间件?微软官方解释:https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/middleware/?tabs=aspnet ...
- AspNetCore Mvc 自定义中间件认证
AspNetCore Mvc 自定义中间件认证 实现控制器访问验证和拦截. 1.注册政策. 例如: services.AddAuthorization(options => { options. ...
- NET Core 1.1 静态文件、路由、自定义中间件、身份验证简介
NET Core 1.1 静态文件.路由.自定义中间件.身份验证简介 概述 之前写过一篇关于<ASP.NET Core 1.0 静态文件.路由.自定义中间件.身份验证简介>的文章,主要 ...
- express中的中间件(middleware)、自定义中间件、静态文件中间件、路由中间件
express文档地址 什么是中间件呢(middleware)?它是谁的中间件呢? 首先我们需要了解到请求和响应, 请求就是客户端发送请求给服务器, 响应就是,服务器根据客户端的请求返回给客户端的数据 ...
- 深入理解自定义ListView
深入理解自定义ListView ListView原理 他是一个系统的原生控件,用列表的形式来显示内容.如果内容过过有1000条左右,我们可以通过手势的上下滑动来查看数据.ListView也不是爆出OO ...
随机推荐
- a-b(高精度)
我现在已经是才语言中的一员了,我在此献上今日的佳作——a-b(高精度),以下是我的程序及其注释,欢迎各位来观赏,耶! 程序: #include<stdio.h> #include<s ...
- 不错的轮播插件flexslider
http://flexslider.woothemes.com/ $('.flexslider').flexslider({ animation:'slide', //滑动效果:翻页效果,默认为fad ...
- Application_Start
这个时间是在第一次访问网站的时候触发..比如你发布了一个网站,,我第一个来访问,,就会触发这个事件..以后再有人来访问就不会触发了.. 一般的,我们总是以为Application_Start是一个应用 ...
- ProfessionalKnowledgeArchitecture
- Amazon's NoSQL Journey and AWS Operations
AWS: Amazon Web Services 提供了一整套基础设施和应用程序服务,使您几乎能够在云中运行一切应用程序:从企业应用程序和大数据项目,到社交游戏和移动应用程序. 计算类: EC2:弹性 ...
- iOS: plist实例
// // main.m // OSXDemo0601_plist // // Created by yao_yu on 14-6-3. // Copyright (c) 2014年 yao_yu. ...
- CAS单点登录(SSO)完整教程
转:http://blog.csdn.net/frinder/article/details/7969925 CAS单点登录(SSO)完整教程(2012-02-01更新) 一.教程说明 前言 教程目的 ...
- 学习Swift -- 泛型
泛型 泛型代码可以让你写出根据自我需求定义.适用于任何类型的,灵活且可重用的函数和类型.它的可以让你避免重复的代码,用一种清晰和抽象的方式来表达代码的意图. 泛型所解决的问题 先来看一个交换两个int ...
- 学习Swift -- 构造器(中)
构造器(中) 值类型的构造器代理 构造器可以通过调用其它构造器来完成实例的部分构造过程.这一过程称为构造器代理,它能减少多个构造器间的代码重复. 构造器代理的实现规则和形式在值类型和类类型中有所不同. ...
- Hive的MoveTask错误
最近在部署Hive上线,结果在线上线下同时出现了MoveTask报错的现象,虽然两者错误的日志以及错误信息一样,但是经过分析解决又发现两者的原因是不一样的. 首先线下的错误日志: 2015-05-18 ...