Skip to content

Commit f707134

Browse files
committed
feat: support abort signal for MobxMutations (#13)
1 parent 41678f7 commit f707134

File tree

3 files changed

+52
-2
lines changed

3 files changed

+52
-2
lines changed

src/mobx-mutation.test.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,4 +160,43 @@ describe('MobxMutation', () => {
160160
await mobxMutation.mutate();
161161
}).rejects.toThrowError('BAD');
162162
});
163+
164+
it('should be able to do abort using second argument in mutationFn', async () => {
165+
vi.useFakeTimers();
166+
167+
const fakeFetch = (data: any = 'OK', signal?: AbortSignal) => {
168+
return new Promise((resolve, reject) => {
169+
setTimeout(() => {
170+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
171+
mobxMutation.destroy();
172+
}, 200);
173+
const timer = setTimeout(() => resolve(data), 1000);
174+
signal?.addEventListener('abort', () => {
175+
clearTimeout(timer);
176+
reject(signal.reason);
177+
});
178+
vi.runAllTimers();
179+
});
180+
};
181+
182+
const mobxMutation = new MobxMutationMock({
183+
mutationKey: ['test'],
184+
mutationFn: async (_, { signal }) => {
185+
await fakeFetch('OK', signal);
186+
},
187+
});
188+
try {
189+
await mobxMutation.mutate();
190+
await vi.runAllTimersAsync();
191+
expect(false).toBe('abort should happen');
192+
} catch (error) {
193+
if (error instanceof DOMException) {
194+
expect(error.message).toBe('The operation was aborted.');
195+
} else {
196+
expect(false).toBe('error should be DOMException');
197+
}
198+
}
199+
200+
vi.useRealTimers();
201+
});
163202
});

src/mobx-mutation.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ export class MobxMutation<
4343
queryClient,
4444
invalidateQueries,
4545
invalidateByKey: providedInvalidateByKey,
46+
mutationFn,
4647
...restOptions
4748
} = config;
4849
this.abortController = new LinkedAbortController(config.abortSignal);
@@ -71,7 +72,11 @@ export class MobxMutation<
7172
TContext
7273
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
7374
// @ts-expect-error
74-
>(queryClient, this.mutationOptions);
75+
>(queryClient, {
76+
...this.mutationOptions,
77+
mutationFn: (variables) =>
78+
mutationFn?.(variables, { signal: this.abortController.signal }),
79+
});
7580

7681
this.updateResult(this.mutationObserver.getCurrentResult());
7782

src/mobx-mutation.types.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,22 @@ export interface MobxMutationInvalidateQueriesOptions
3636
queryKeys?: InvalidateQueryFilters['queryKey'][];
3737
}
3838

39+
export type MobxMutationFunction<TData = unknown, TVariables = unknown> = (
40+
variables: TVariables,
41+
options: { signal: AbortSignal },
42+
) => Promise<TData>;
43+
3944
export interface MobxMutationConfig<
4045
TData = unknown,
4146
TVariables = void,
4247
TError = DefaultError,
4348
TContext = unknown,
4449
> extends Omit<
4550
MutationObserverOptions<TData, TError, TVariables, TContext>,
46-
'_defaulted'
51+
'_defaulted' | 'mutationFn'
4752
>,
4853
MobxMutationFeatures {
54+
mutationFn?: MobxMutationFunction<TData, TVariables>;
4955
queryClient: AnyQueryClient;
5056
abortSignal?: AbortSignal;
5157
invalidateQueries?:

0 commit comments

Comments
 (0)