带TS的Redux工具包:建议分派两个连续的异步thunk操作的方法是什么

问题描述

最近,当我尝试使用两个不同版本的API时遇到了这个问题。逻辑是如果API的v2给我一个404错误,那么我将尝试v1,如果没有错误,我将使用v2

的结果

这是我的尝试:我为每个版本创建了两个单独的异步thunk动作,然后在分配两个动作的地方创建了一个异步thunk。

export const getV2LoggingOptions = createAsyncThunk(
  "settings/getV2LoggingOptions",async () => {
    return sdkClient.getV2LoggingOptions().promise();
  }
);

export const getV1LoggingOptions = createAsyncThunk(
  "settings/getV1LoggingOptions",async () => {
    return sdkClient.getV1LoggingOptions().promise();
  }
);

export const getLoggingOptions = createAsyncThunk(
  "settings/getLoggingOptions",async (arg,thunkApi) => {
    let response = await thunkApi.dispatch(getV2LoggingOptions());
    if (response.error) {
      if (
        response.error.statusCode === "404"
      ) {
        response = await thunkApi.dispatch(getV1LoggingOptions());
      }

      throw response.error;
    }

    return response.payload;
  }
);

我认为这种方法可行。但不确定这是否是最好的方法。现在,这种方法存在两个问题:

  1. 我不知道如何像let response = await thunkApi.dispatch(getV2LoggingOptions());那样正确键入此响应。
  2. 此外,error内部的response属性(如果v2调用失败)不包含statusCode属性。所以我看不懂对于它为什么不包含statusCode
  3. 的问题,这确实令我感到困惑

另一种方法是只创建一个异步thunk并直接在内部调用两个版本

export const getLoggingOptions = createAsyncThunk(
  "settings/getLoggingOptions",async () => {
    let response;
    try {
      response = await sdkClient.getV2LoggingOptions().promise();
    } catch (error) {
      if (
        error.statusCode === "404"
      ) {
        response = await sdkClient.getV1LoggingOptions().promise();
      }
      throw error;
    }

    return response;
  }
);

它似乎也在工作。但是问题是,我仍然不确定如何在此处键入response

API确实提供了其响应的输入方式。 GetV1LoggingOptionsResponseGetV2LoggingOptionsResponse。但是我不确定应该将响应键入为

let response: GetV1LoggingOptionsResponse | GetV2LoggingOptionsResponse

从那时起,我只能从响应中读取这两种类型的重叠部分。

在第二种方法中,statusCode也被error子句中的catch所丢失。

解决方法

由于两个api都有不同的返回值,因此它们可能应该是不同的asyncThunks,因此您应该分别处理它们的操作。 另外,您应该在相应的asyncThunks内部进行错误处理(包括抛出),因为这将导致您可以在化简器中处理rejected动作。

一旦有了这两个asyncThunk,就没有理由再使用第三个asyncThunk来介绍它自己实际上不需要的生命周期操作,因为这实际上只是另外两个的编排。

写一个普通的thunk:


const getLogginOptions = () => async (dispatch) => {
  let result = await dispatch(getV2LoggingOptions());
  if (getV2LoggingOptions.rejected.match(result)) {
    result =  await dispatch(getV1LoggingOptions());
  }
  return result;
}