Redux 处理异步 Action
redux-promise-utils
What
redux-promise-utils
是一个基于 redux-thunk
和 redux-actions
的工具,符合 FSA 规范,方便开发者处理异步 Action,减少大量冗余的 template 代码。
Why
redux 一开始的设计就是用于处理同步的 Action。通过调用 Action 函数后 dispatch 返回的 type 和 payload ,最终交由 reducer 处理。reducer 匹配到相应的 type 并进行处理。
说到 redux 处理异步 Action,最为人熟知的就是 redux-thunk
。redux-thunk
是一个 middleware,它可以在 reducer 延迟处理 Action,并在异步的相应回调中再 dispatch Action。所以我们可以认为 redux-thunk 其实不是专门处理异步用的 middleware,而是可能会延迟执行 dispatch 的函数。
常规 redux-thunk
在大多数的 redux-thunk
规范中,对一个请求需要定义三种Action,发起请求前,请求成功后,请求失败后。一般代码都是如下所示。
// constant/actionType.js
export default {
FETCH: 'FETCH_LIST_START',
FETCH_SUCCESSED: 'FETCH_LIST_SUCCESSED',
FETCH_FAILED: 'FETCH_LIST_FAILED'
}
// data/action.js
import ACTION_TYPE from '../constant/actionType'
import * as api from './api'
// start fetch
export function fetchAction(options) {
return dispatch => {
dispatch({
type: ACTION_TYPE.FETCH_LIST,
payload: options
})
return api.fetchList(options)
.then((response) => {
dispatch({
type: ACTION_TYPE.FETCH_LIST_SUCCESSED,
payload: {
options,
response
}
})
})
.catch((response) => {
dispatch({
type: ACTION_TYPE.FETCH_LIST_FAILED,
payload: {
options,
response
}
})
})
}
}
// data/reducer.js
import ACTION_TYPE from '../constant/actionType'
const initState = {}
export function reducer(state = initState, action) {
switch(action.type) {
case ACTION_TYPE.FETCH_LIST:
// your handler
return state
case ACTION_TYPE.FETCH_LIST_SUCCESSED:
// your handler
return state
case ACTION_TYPE.FETCH_LIST_FAILED:
// your handler
return state
default:
return state
}
}
一个简单的请求 Action 需要如此多的 template 代码。一旦业务量起来后,几十上百个的异步请求都需要复制粘贴大量代码,实在是非常的难受。
异步处理 redux-promise
当开发者都感受到痛苦后,自然会出头解决问题,redux-promise
就是解决方案。
redux-promise
提供了一个简单创建 promise action 的方法,并提供配套的 middleware 处理 promise 化的 action。整套代码精简了特别多,大致如下。
// data/action.js
import { createAction } from 'redux-promise'
import * as api from './api'
import ACTION_TYPE from '../constant/actionType'
export const fetchAction = createAction(ACTION_TYPE.FETCH_LIST, api.fetchList)
// data/reducer.js
import { fetchAction } from './action.js'
import ACTION_TYPE from '../constant/actionType'
const initState = {}
return (state = initState, action) => {
switch(action.type) {
case ACTION_TYPE.FETCH_LIST:
if(!action.error) {
// your success handler
} else {
// your failed handler
}
return state
default:
return state
}
}
/*
当然在基于 redux-actions,使用 handleAction 是可以省略 actionType.js 文件和定义的 ACTION_TYPE 的。
这里为了更清晰展现大家熟悉的 switch case 式的 reducer 就没有展示出来了。
*/
这一看,代码似乎精简了许多,不需要对一个接口定义三个 actionType 了。但是 redux-promise 只能处理两种状态了,异步后的成功/失败态。实际使用上,似乎也没什么影响,毕竟 redux 天然支持同步 action,所以你就在调异步 action 前再调一个同步 action ,那个 action 来当作 FETCH_LIST_START
来使用。
所以我们把定义一个异步 Action 和对应的三个 actionType ,转变为定义两个 Action 和对应的 actionType,且破坏了一个异步 Action 的内聚性,导致本身一个异步 Action 造成的 state 变化,被拆成了两个去维护,实在有失优雅和代码相应的维护性。
redux-promise-utils
综上所述,我认为 redux-thunk
还是一个更为合理的方案,我们是否能基于 redux-thunk
然后降低我们过于冗余的代码呢。我们来看看到底 redux-thunk
有哪些麻烦的操作我们需要来优化。
- 每次都需要执行 promise 方法后,内部手动去 dispatch 各个状态给 reducer 进行处理。
- 一个异步 Action 需要定义三个特定的 actionType。
- 需要维护一个的 actionType 文件,并提供给 action / reducer 使用。
最终 redux-promise-utils 处理了这三个问题,我们一起来看看最终代码是怎样的。
// data/action.js
import { createPromiseAction } from 'redux-promise-utils'
import * as api from './api'
export const fetchAction = createPromiseAction('fetchList', api.fetchList)
// data/reducer.js
import { createReducer } from 'redux-promise-utils'
import { fetchAction } from './action'
const initState = {}
const reducer = createReducer(initState)
// 获取同步数据
.which(SYNC_ACTION, (state, action) => {
return action
})
// 获取异步数据
.asyncWhich(fetchAction, {
start(state, action) {
return state
},
success(state, action) {
return state
},
fail(state, action) {
return state
}
})
// 构建 redux 需要的 reducer 方法
.build()
export default reducer
代码精简了许多,上述的三个问题都 say goodbye 了。除了 reducer 不再使用 switch case 模式去处理,并没有特别多的区别。那到底 createPromiseAction / createReducer 做了哪些处理,下面会讲到。
How
redux-promise-uitls
核心是基于 redux-thunk
和 redux-actions
。
先来看看 createPromiseAction,核心就是内置三个执行状态,并基于 promise 下自动 dispatch 相应的状态。所以内部会按一定的规则,根据提供的 type 派生出三种状态,分别是 ${type}_START
/ ${type}_SUCCESS
/ ${type}_FAILED
。得益于 redux-thunk
,即使不用配套提供的 createReducer 处理,也可以手动处理这三种状态。但使用了 createReducer 则会更加顺畅,包括不需要再维护 actionType,不用单独处理派生出的三种状态。
而 createReducer 内部,对 asyncWhich(type, handlerOptions)
捕获到的 action,会根据 start/success/fail 三个函数自动处理,不需要写多余的 type。which(type, handler)
捕获的则是普通的同步函数,和以往的 reducer 写法是一样的。
createReducer 会对 type 执行一次 type.toString()
,而 createPromiseAction 借鉴 redux-actions
的 createAction 一样,会重写 type.toString
方法,所以也不需要再独立维护一套 actionType.js 相应的配置文件。
这些操作都是为了让开发者可以逃离大部分无意义的 template 代码,来提高每日的编码体验。
赶快来点星星吧
Github: redux-promise-utils
Redux 处理异步 Action的更多相关文章
- redux学习日志:关于异步action
当我们在执行某个动作的时候,会直接dispatch(action),此时state会立即更新,但是如果这个动作是个异步的呢,我们要等结果出来了才能知道要更新什么样的state(比如ajax请求),那就 ...
- 25.redux回顾,redux中的action函数异步
回顾:Redux: 类似于 Vuex 概念:store/reducer/action action:动作 {type,.....} 一定要有type 其他属性不做限制 reducer:通过计算产生st ...
- 【React全家桶入门之十三】Redux中间件与异步action
在上一篇中我们了解到,更新Redux中状态的流程是这种:action -> reducer -> new state. 文中也讲到.action是一个普通的javascript对象.red ...
- Redux学习笔记--异步Action和Middleware
异步Action 之前介绍的都是同步操作,Redux通过分发action处理state,所有的数据流都是同步的,如果需要一步的话怎么办? 最简单的方式就是使用同步的方式来异步,将原来同步时一个acti ...
- redux-amrc:用更少的代码发起异步 action
很多人说 Redux 代码多,开发效率低.其实 Redux 是可以灵活使用以及拓展的,经过充分定制的 Redux 其实写不了几行代码.今天先介绍一个很好用的 Redux 拓展-- redux-amrc ...
- 异步action和redux-thunk理解
异步action一般指的就是异步action创建函数 action创建函数分为同步action创建函数和异步action创建函数 同步action创建函数(最常见的): function reques ...
- ASP.NET MVC下的异步Action的定义和执行原理
一.基于线程池的请求处理ASP.NET通过线程池的机制处理并发的HTTP请求.一个Web应用内部维护着一个线程池,当探测到抵达的针对本应用的请求时,会从池中获取一个空闲的线程来处理该请求.当处理完毕, ...
- ASP.NET MVC什么时候使用异步Action
在没有使用异步Action之前,在Action内,比如有如下的写法: public ActionResult Index() CustomerHelper cHelper = new Customer ...
- ASP.NET MVC下的异步Action的定义和执行原理[转]
http://www.cnblogs.com/artech/archive/2012/06/20/async-action-in-mvc.html Visual Studio提供的Controller ...
随机推荐
- PythonInstaller编译EXE方法+编译过程出错方案大全
https://www.cnblogs.com/gopythoner/p/6337543.htmlhttps://www.zhihu.com/question/22963200https://blog ...
- UVA-1605 Building for UN (构造)
题目大意:n个国家的人要在一栋大厦里办公,要求任意两个国家的办公室要相邻(同层同边或邻层同面),设计一个满足要求的方案. 题目分析:题目限制较少,任意构造出一个解即可. 代码如下: # include ...
- AppCrawler自动化遍历使用详解(版本2.1.0 )
AppCrawle是自动遍历的app爬虫工具,最大的特点是灵活性,实现:对整个APP的所有可点击元素进行遍历点击. 优点: 1.支持android和iOS, 支持真机和模拟器 2.可通过配置来设定 ...
- For循环重复代码的重构
DRY(don't repeat yourself),重复往往是代码腐烂的开始,我们一般的处理手法是将重复的代码提取成一个方法,然后用新方法替换掉原来的代码. 但是对于for循环里面的重复代码要如何处 ...
- 你以为在用SharePoint但其实不是
博客地址 http://blog.csdn.net/foxdave 原文链接:http://www.techrepublic.com/blog/tech-decision-maker/you-thin ...
- Beta阶段第1周/共2周 Scrum立会报告+燃尽图 01
作业要求[https://edu.cnblogs.com/campus/nenu/2018fall/homework/2383] 版本控制:https://git.coding.net/liuyy08 ...
- New Concept English Two 3
$课文5 无错号之虞 47. Mr.James Scott has a garage in Silbury and now he has just bought another garage in P ...
- 新书《Cocos2dx 3.x 3D图形学渲染技术讲解》问世
笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,已出版书籍:<手把手教你架构3D游戏引擎>电子工业出版社和<Unity3D实战核心技术详解 ...
- ios系统降级
1.使用PP助手/iTunes备份好文件资料,以防重要信息丢失: 2.设备连接iTunes,按住Shift键之后点击“恢复iPhone”,选择已下载好的iOS8.4.1固件,等待更新完成即可. 注意要 ...
- BZOJ5312: 冒险【线段树】【位运算】
Description Kaiser终于成为冒险协会的一员,这次冒险协会派他去冒险,他来到一处古墓,却被大门上的守护神挡住了去路,守护神给出了一个问题, 只有答对了问题才能进入,守护神给出了一个自然数 ...