Handle createAppAsyncThunk rejected actions in the errors middleware (#29791)

This commit is contained in:
Renaud Chaput 2024-03-29 14:57:39 +01:00 committed by GitHub
parent f96648d41c
commit 69e5771881
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 28 additions and 7 deletions

View File

@ -1,16 +1,27 @@
import { isAction } from '@reduxjs/toolkit'; import {
isAction,
isAsyncThunkAction,
isRejectedWithValue,
} from '@reduxjs/toolkit';
import type { Action, Middleware } from '@reduxjs/toolkit'; import type { Action, Middleware } from '@reduxjs/toolkit';
import type { RootState } from '..'; import type { RootState } from '..';
import { showAlertForError } from '../../actions/alerts'; import { showAlertForError } from '../../actions/alerts';
import type { AsyncThunkRejectValue } from '../typed_functions';
const defaultFailSuffix = 'FAIL'; const defaultFailSuffix = 'FAIL';
const isFailedAction = new RegExp(`${defaultFailSuffix}$`, 'g'); const isFailedAction = new RegExp(`${defaultFailSuffix}$`, 'g');
interface ActionWithMaybeAlertParams extends Action { interface ActionWithMaybeAlertParams extends Action, AsyncThunkRejectValue {}
skipAlert?: boolean;
skipNotFound?: boolean; interface RejectedAction extends Action {
error?: unknown; payload: AsyncThunkRejectValue;
}
function isRejectedActionWithPayload(
action: unknown,
): action is RejectedAction {
return isAsyncThunkAction(action) && isRejectedWithValue(action);
} }
function isActionWithmaybeAlertParams( function isActionWithmaybeAlertParams(
@ -23,7 +34,11 @@ export const errorsMiddleware: Middleware<Record<string, never>, RootState> =
({ dispatch }) => ({ dispatch }) =>
(next) => (next) =>
(action) => { (action) => {
if ( if (isRejectedActionWithPayload(action) && !action.payload.skipAlert) {
dispatch(
showAlertForError(action.payload.error, action.payload.skipNotFound),
);
} else if (
isActionWithmaybeAlertParams(action) && isActionWithmaybeAlertParams(action) &&
!action.skipAlert && !action.skipAlert &&
action.type.match(isFailedAction) action.type.match(isFailedAction)

View File

@ -7,8 +7,14 @@ import type { AppDispatch, RootState } from './store';
export const useAppDispatch = useDispatch.withTypes<AppDispatch>(); export const useAppDispatch = useDispatch.withTypes<AppDispatch>();
export const useAppSelector = useSelector.withTypes<RootState>(); export const useAppSelector = useSelector.withTypes<RootState>();
export interface AsyncThunkRejectValue {
skipAlert?: boolean;
skipNotFound?: boolean;
error?: unknown;
}
export const createAppAsyncThunk = createAsyncThunk.withTypes<{ export const createAppAsyncThunk = createAsyncThunk.withTypes<{
state: RootState; state: RootState;
dispatch: AppDispatch; dispatch: AppDispatch;
rejectValue: string; rejectValue: AsyncThunkRejectValue;
}>(); }>();