I want to create createAsyncThunk function wrapper, because want to refactor 3 big thunks in one with parameters. Here my solution.
Code
export const getExportThunk = <T>(
handler: (args: T) => Promise<boolean>,
route: string,
successText: string
) =>
createAsyncThunk<boolean, T>(
route,
async (args, {rejectWithValue, dispatch}) => {
try {
const res = await handler(args);
return true;
} catch (e: unknown) {
return rejectWithValue('unknown');
}
}
);
Usage.
export const exportWorkload = getExportThunk<IServerGetWorkloadBody>(
api.exportWorkload,
'ytd/exportWorkload',
'YTD Workload was successfully downloaded!'
);
But when I'm trying to dispatch the result of getExportThunk, I catch an error that says: this is undefined. How to pass context in this case and moreover which context it should be?
Error stacktrace: stacktrace
Place where redux promise function fails
const promise = (async function () {
let finalAction: ReturnType<typeof fulfilled | typeof rejected>
try {
let conditionResult = options?.condition?.(arg, { getState, extra })
if (isThenable(conditionResult)) {
conditionResult = await conditionResult
}
if (conditionResult === false) {
// eslint-disable-next-line no-throw-literal
throw {
name: 'ConditionError',
message: 'Aborted due to condition callback returning false.',
}
}
started = true
dispatch(
pending(
requestId,
arg,
options?.getPendingMeta?.({ requestId, arg }, { getState, extra })
)
)
//fails in this asignment
finalAction = await Promise.race([
abortedPromise,
Promise.resolve(
payloadCreator(arg, {
dispatch,
getState,
extra,
requestId,
signal: abortController.signal,
rejectWithValue: ((
value: RejectedValue,
meta?: RejectedMeta
) => {
return new RejectWithValue(value, meta)
}) as any,
fulfillWithValue: ((value: unknown, meta?: FulfilledMeta) => {
return new FulfillWithMeta(value, meta)
}) as any,
})
).then((result) => {
if (result instanceof RejectWithValue) {
throw result
}
if (result instanceof FulfillWithMeta) {
return fulfilled(result.payload, requestId, arg, result.meta)
}
return fulfilled(result as any, requestId, arg)
}),
])
} catch (err) {
finalAction =
err instanceof RejectWithValue
? rejected(null, requestId, arg, err.payload, err.meta)
: rejected(err as any, requestId, arg)
}
As @markerikson said, the problem was with context of api.exportWorkload, it was loosing its context after firing it as handler() and was trying to get access to it. The solution.
export const exportWorkload = getExportThunk<IServerGetWorkloadBody>(
api.exportWorkload.bind(api),
'ytd/exportWorkload',
'YTD Workload was successfully downloaded!'
);
Or use arrow function instead default function
public exportWorkload = async (body: IServerGetWorkloadBody) => {
const res = await this.ytdService.exportWorkload(body);
return res;
};