Redux 处理异步 Action

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

转载于:https://www.cnblogs.com/YikaJ/p/9687588.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Redux中,异步操作可以通过中间件来处理。在Redux中,中间件是一种函数,它可以拦截派发到Store中的Action,并在必要时对其进行操作。常见的Redux中间件有Redux Thunk、Redux Saga和Redux Observable等。 其中,Redux Thunk是Redux官方提供的中间件之一,它允许Action Creator返回一个函数而不是一个对象。在这个函数中,我们可以执行异步操作并在操作完成后再派发一个Action来更新应用程序状态。 例如,我们可以编写一个异步Action Creator来获取用户列表: ```javascript const fetchUsers = () => { return (dispatch) => { dispatch({ type: 'FETCH_USERS_REQUEST' }); return fetch('/users') .then(response => response.json()) .then(data => { dispatch({ type: 'FETCH_USERS_SUCCESS', payload: data }); }) .catch(error => { dispatch({ type: 'FETCH_USERS_FAILURE', payload: error }); }); }; }; ``` 在上面的代码中,我们通过返回一个函数来处理异步操作。在函数中,我们首先派发一个FETCH_USERS_REQUEST Action来表示开始获取用户列表,然后执行异步操作。当异步操作完成后,我们再派发一个FETCH_USERS_SUCCESS Action来更新应用程序状态,并将获取到的用户列表作为payload传递给Action。如果异步操作失败,我们将派发一个FETCH_USERS_FAILURE Action来通知应用程序。 通过这种方式,我们可以在Redux处理异步操作,并保持应用程序的状态可预测性和一致性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值