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,发起请求前,请求成功后,请求失败后。一般代码都是如下所示。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55// 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。整套代码精简了特别多,大致如下。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26// 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 处理了这三个问题,我们一起来看看最终代码是怎样的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28// 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
转载于:https://www.cnblogs.com/YikaJ/p/9687588.html
最后
以上就是靓丽钢笔最近收集整理的关于Redux 处理异步 Actionredux-promise-utils的全部内容,更多相关Redux内容请搜索靠谱客的其他文章。
发表评论 取消回复