Как я могу применить DRY при использовании Redux Toolkit asyncThunkCreator

avatar
Hammersholt
1 июля 2021 в 18:06
90
1
1

у меня есть вопрос, связанный с RTK, так как я хочу иметь возможность отменить любой сделанный запрос, я повторяю код в большинстве моих создателей действий, созданных с помощью createAsyncThunk

Я хотел бы создать своего рода обертку, но у меня возникли проблемы с ее набором текста. Аргументы, используемые в createAsyncThunk, выставлены где-то или?

Копаясь в коде, я вижу, что thunkAPI (который меня больше всего интересует) определяется с помощью GetThunkAPI<'3-й параметр'> с 3 машинописными параметрами

создатель действий может выглядеть примерно так

export const resendValidationKey = createAsyncThunk<
  void,
  IAdminResendValidationKey,
  { rejectValue: AxiosError }
>('admin/resendValidationKey', async (data, thunkAPI) => {
  const { signal, rejectWithValue } = thunkAPI;
  try {
    const source = axios.CancelToken.source();
    signal.addEventListener('abort', () => {
      source.cancel();
    });
    await const response = axios.post(`admin/account/validate/resend`, data, {
      cancelToken: source.token,
    });
    return response.data;
  } catch (error) {
    return rejectWithValue(error);
  }
});

в идеале мне нужна какая-то оболочка, я просто передаю URL, метод, данные и обратный вызов успеха (если есть), это вообще возможно?

Надеюсь, все это имеет смысл?

Источник

Ответы (1)

avatar
Lucas Basquerotto
4 ноября 2021 в 19:33
0

Я создал оболочку вокруг createAsyncThunk следующим образом:

import type { AsyncThunkPayloadCreator } from '@reduxjs/toolkit';
import { createAsyncThunk } from '@reduxjs/toolkit';
//...

const handleReduxResult = async <T>(
    actionName: string,
    fn: () => T | Promise<T> 
    rejectWithValue: (value: unknown) => unknown,
) => {
    try {
        return await fn();
    } catch (e: unknown) {
        const wrappedError = wrapErrorTyped(e);
        wrappedError.actionName = actionName;
        const wrappedSerializedError = createWrappedSerializedError(wrappedError);
        return rejectWithValue(wrappedSerializedError) as T;
    }
};

export interface CustomAsyncThunkConfig {
    [prop: string]: unknown;
}

export const createCustomAsyncThunk = <Returned, ThunkArg = void>(
    name: string,
    thunk: AsyncThunkPayloadCreator<Returned, ThunkArg, CustomAsyncThunkConfig> 
) =>
    createAsyncThunk<Returned, ThunkArg, CustomAsyncThunkConfig>(
        name,
        async (params, thunkApi) =>
            await handleReduxResult(
                name,
                async () => thunk(params, thunkApi),
                thunkApi.rejectWithValue,
            ),
    );

В моем случае я хочу обрабатывать пользовательские ошибки, которые могут быть вызваны функцией, вызываемой в преобразователе, но вместо этого инструментарий редукции создает свою собственную ошибку, которая выдается, когда результат преобразования разворачивается, что недопустимо в нашем случае. установка.

Этого можно избежать, вызвав функцию rejectWithValue, присутствующую во втором параметре функции thunk, но, к сожалению, вызывать ее каждый раз было бы очень плохо, поскольку приходится включать много шаблонов.

Чтобы обойти это, мы создали оболочку вокруг createAsyncThunk, что не очень просто, поскольку используемые в ней типы очень сложны, и многие из них не экспортируются.

В любом случае мне удалось создать оболочку, которая вызывает функцию handleReduxResult, которая обрабатывает ошибку, создавая пользовательскую ошибку в формате, который мы используем для ошибок, а также включая actionName чтобы дать больше информации об ошибке в журналах, и мы, наконец, сериализуем ее и отправляем на rejectWithValue (который ожидает сериализованное значение).

Обработка ошибок специфична для нашего случая, вы можете изменить функцию handleReduxResult на некоторый минимальный код, например:

const handleReduxResult = async <T>(
    actionName: string,
    fn: () => T | Promise<T> 
    rejectWithValue: (value: unknown) => unknown,
) => {
    return await fn();
};

а затем внесите изменения в соответствии с вашим вариантом использования.