redux-promise-utils

What

redux-promise-utils 是一个基于 redux-thunkredux-actions 的工具,符合 FSA 规范,方便开发者处理异步 Action,减少大量冗余的 template 代码。

Why

redux 一开始的设计就是用于处理同步的 Action。通过调用 Action 函数后 dispatch 返回的 type 和 payload ,最终交由 reducer 处理。reducer 匹配到相应的 type 并进行处理。

说到 redux 处理异步 Action,最为人熟知的就是 redux-thunkredux-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 有哪些麻烦的操作我们需要来优化。

  1. 每次都需要执行 promise 方法后,内部手动去 dispatch 各个状态给 reducer 进行处理。
  2. 一个异步 Action 需要定义三个特定的 actionType。
  3. 需要维护一个的 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-thunkredux-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的更多相关文章

  1. redux学习日志:关于异步action

    当我们在执行某个动作的时候,会直接dispatch(action),此时state会立即更新,但是如果这个动作是个异步的呢,我们要等结果出来了才能知道要更新什么样的state(比如ajax请求),那就 ...

  2. 25.redux回顾,redux中的action函数异步

    回顾:Redux: 类似于 Vuex 概念:store/reducer/action action:动作 {type,.....} 一定要有type 其他属性不做限制 reducer:通过计算产生st ...

  3. 【React全家桶入门之十三】Redux中间件与异步action

    在上一篇中我们了解到,更新Redux中状态的流程是这种:action -> reducer -> new state. 文中也讲到.action是一个普通的javascript对象.red ...

  4. Redux学习笔记--异步Action和Middleware

    异步Action 之前介绍的都是同步操作,Redux通过分发action处理state,所有的数据流都是同步的,如果需要一步的话怎么办? 最简单的方式就是使用同步的方式来异步,将原来同步时一个acti ...

  5. redux-amrc:用更少的代码发起异步 action

    很多人说 Redux 代码多,开发效率低.其实 Redux 是可以灵活使用以及拓展的,经过充分定制的 Redux 其实写不了几行代码.今天先介绍一个很好用的 Redux 拓展-- redux-amrc ...

  6. 异步action和redux-thunk理解

    异步action一般指的就是异步action创建函数 action创建函数分为同步action创建函数和异步action创建函数 同步action创建函数(最常见的): function reques ...

  7. ASP.NET MVC下的异步Action的定义和执行原理

    一.基于线程池的请求处理ASP.NET通过线程池的机制处理并发的HTTP请求.一个Web应用内部维护着一个线程池,当探测到抵达的针对本应用的请求时,会从池中获取一个空闲的线程来处理该请求.当处理完毕, ...

  8. ASP.NET MVC什么时候使用异步Action

    在没有使用异步Action之前,在Action内,比如有如下的写法: public ActionResult Index() CustomerHelper cHelper = new Customer ...

  9. ASP.NET MVC下的异步Action的定义和执行原理[转]

    http://www.cnblogs.com/artech/archive/2012/06/20/async-action-in-mvc.html Visual Studio提供的Controller ...

随机推荐

  1. supervisor进程管理工具

    Supervisor 一个python写的进程管理工具,用来启动.关闭.重启进程,可以同时控制多个进程. 安装: pip install supervisor 配置: 通过配置文件来满足自己的需求 配 ...

  2. oracle会自动收集统计信息-记住哦

    oracle自动收集统计信息,周一至周五  时间:22:00:00 oracle自动收集统计信息,周六.周日  时间:06:00:00

  3. windowplayer播放列表属性

    ArrayList a = new ArrayList(); a.Add("c:\\kugou\\林宇中 - 干物女.mp3"); a.Add("c:\\kugou\\海 ...

  4. springboot模糊查询

    在学习MyBatis过程中想实现模糊查询,可惜失败了.后来上百度上查了一下,算是解决了.记录一下MyBatis实现模糊查询的几种方式. 数据库表名为test_student,初始化了几条记录,如图: ...

  5. bzoj2442

    题解: 单调队列+dp f[i]=max(f[j-1]+sum[i]-sum[j]) 然后维护f[j-1]-sum[j]单调性 代码: #include<bits/stdc++.h> us ...

  6. Vivado_MicroBlaze_问题及解决方法_汇总(不定时更新)

    Vivado_MicroBlaze_问题及解决方法_汇总(不定时更新) 标签: Vivado 2015-07-03 14:35 4453人阅读 评论(0) 收藏 举报  分类: 硬件(14)  版权声 ...

  7. c# 添加注册表

  8. WindowsXamlHost:在 WPF 中使用 UWP 的控件(Windows Community Toolkit)

    Windows Community Toolkit 再次更新到 5.0.以前可以在 WPF 中使用有限的 UWP 控件,而现在有了 WindowsXamlHost,则可以使用更多 UWP 原生控件了. ...

  9. .NET IL指令速查表

    名称 说明 Add 将两个值相加并将结果推送到计算堆栈上. Add.Ovf 将两个整数相加,执行溢出检查,并且将结果推送到计算堆栈上. Add.Ovf.Un 将两个无符号整数值相加,执行溢出检查,并且 ...

  10. 1106 1014 C语言文法定义与C程序的推导过程 冒泡程序语法树