一种使用 createAsyncThunk 触发多个异步操作的简洁方法

Posted

技术标签:

【中文标题】一种使用 createAsyncThunk 触发多个异步操作的简洁方法【英文标题】:A clean way for an action to fire multiple asynchronous actions with createAsyncThunk 【发布时间】:2020-12-15 02:47:54 【问题描述】:

我们将延迟渲染我们的 React-Redux Web 应用程序,直到 Redux 商店中的几个异步应用程序初始化任务完成。

这是设置商店然后触发初始化操作的代码:

export const setupStoreAsync = () => 
    return new Promise((resolve, reject) => 
        const store = setupStore()
        store
            .dispatch(fetchAppInitialization())
            .then(unwrapResult)
            .then(_ => resolve(store))
            .catch(e => reject(e.message))
    )

promise 拒绝非常重要,因为它用于为用户呈现错误消息,以防应用无法正确设置。这段代码读起来非常好,效果也很好。

问题在于动作创建者:

export const fetchAppInitialization = createAsyncThunk(
    'app/initialization',
    (_, thunkApi) =>
        new Promise((resolve, reject) =>
            Promise.all([thunkApi.dispatch(fetchVersionInfo())]).then(results => 
                results.map(result => result.action.error && reject(result.error))
            )
        )
)

这段代码运行良好。如果这些操作中的任何一个失败,则 Promise 将被拒绝,并且用户会看到一条错误消息。但它很丑 - 它不像我们正常的动作创作者那么漂亮:

export const fetchVersionInfo = createAction('system/versionInfo', _ => (
    payload: 
        request:  url: `/system/versionInfo` ,
    ,
))

我们有时会在fetchAppInitialization 中触发多个获取请求,因此Promise.all 函数肯定是必需的。我们希望能够使用 Redux-Toolkit 的 createAction 语法来触发多个承诺操作,以缩短此操作创建器,但我不知道这是否可能。

注意:我使用redux-requests 来处理我的 axios 请求。

createAsyncThunk 甚至是必需的吗?

【问题讨论】:

您是否在使用生成的生命周期操作?如果不是,是的,你有点过头了,可以用.catch 把它移到你的 setupStoreAsync 中;) 【参考方案1】:

由于除了这个单一的用例之外我没有使用 fetchAppInitialization 操作,因此我只是将其删除并将逻辑直接移动到 setupStoreAsync 函数中。这有点紧凑。这不是最优的,因为仍然包含results.map 逻辑,但至少我们不再使用createAsyncThunk

export const setupStoreAsync = () => 
    return new Promise((resolve, reject) => 
        const store = setupStore()

        new Promise((resolve, reject) =>
            Promise.all([store.dispatch(fetchVersionInfo())]).then(results => 
                results.map(result => result.action.error && reject(result.error))
                resolve()
            )
        )
            .then(_ => resolve(store))
            .catch(e => reject(e.message))
    )


更新:我可以使用async/await 使代码更漂亮。

export const setupStoreAsync = async () => 
    const store = setupStore()

    const results = await Promise.all([store.dispatch(fetchVersionInfo())])
    results.forEach(result => 
        if (result.action.error) throw result.error
    )
    return store

【讨论】:

请注意,您可以使用async/await 而不是new Promise 来缩短该逻辑。

以上是关于一种使用 createAsyncThunk 触发多个异步操作的简洁方法的主要内容,如果未能解决你的问题,请参考以下文章

使用axios时如何在createAsyncThunk中创建payload

createAsyncThunk:错误:无法使用两个 reducer 调用相同操作类型的 addCase

createAsyncThunk 和使用 redux-toolkit 编写 reducer 登录

如何正确使用带有 typescript 的 createAsyncThunk 函数?

刷新页面时 CreateAsyncThunk 不起作用

我可以使用 redux 工具包访问带有 axios 的 createAsyncThunk 中的状态吗?