Skip to content

Commit 90ff485

Browse files
committed
Treat thunk abort signal the same as a false condition result
1 parent 87bebec commit 90ff485

File tree

2 files changed

+30
-12
lines changed

2 files changed

+30
-12
lines changed

packages/toolkit/src/createAsyncThunk.ts

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -590,18 +590,10 @@ If you want to use the AbortController to react to \`abort\` events, please cons
590590
const abortController = new AC()
591591
let abortReason: string | undefined
592592

593-
const abortedPromise = new Promise<never>((_, reject) =>
594-
abortController.signal.addEventListener('abort', () =>
595-
reject({ name: 'AbortError', message: abortReason || 'Aborted' })
596-
)
597-
)
598-
599593
let started = false
600594
function abort(reason?: string) {
601-
if (started) {
602-
abortReason = reason
603-
abortController.abort()
604-
}
595+
abortReason = reason
596+
abortController.abort()
605597
}
606598

607599
const promise = (async function () {
@@ -611,14 +603,24 @@ If you want to use the AbortController to react to \`abort\` events, please cons
611603
if (isThenable(conditionResult)) {
612604
conditionResult = await conditionResult
613605
}
614-
if (conditionResult === false) {
606+
607+
if (conditionResult === false || abortController.signal.aborted) {
615608
// eslint-disable-next-line no-throw-literal
616609
throw {
617610
name: 'ConditionError',
618611
message: 'Aborted due to condition callback returning false.',
619612
}
620613
}
621614
started = true
615+
616+
const abortedPromise = new Promise<never>((_, reject) =>
617+
abortController.signal.addEventListener('abort', () =>
618+
reject({
619+
name: 'AbortError',
620+
message: abortReason || 'Aborted',
621+
})
622+
)
623+
)
622624
dispatch(
623625
pending(
624626
requestId,

packages/toolkit/src/tests/createAsyncThunk.test.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
getLog,
1414
} from 'console-testing-library/pure'
1515
import { expectType } from './helpers'
16+
import { delay } from '../utils'
1617

1718
declare global {
1819
interface Window {
@@ -621,6 +622,21 @@ describe('conditional skipping of asyncThunks', () => {
621622
)
622623
})
623624

625+
test('async condition with AbortController signal first', async () => {
626+
const condition = async () => {
627+
await delay(25)
628+
return true
629+
}
630+
const asyncThunk = createAsyncThunk('test', payloadCreator, { condition })
631+
632+
try {
633+
const thunkPromise = asyncThunk(arg)(dispatch, getState, extra)
634+
thunkPromise.abort()
635+
await thunkPromise
636+
} catch (err) {}
637+
expect(dispatch).toHaveBeenCalledTimes(0)
638+
})
639+
624640
test('rejected action is not dispatched by default', async () => {
625641
const asyncThunk = createAsyncThunk('test', payloadCreator, { condition })
626642
await asyncThunk(arg)(dispatch, getState, extra)
@@ -630,7 +646,7 @@ describe('conditional skipping of asyncThunks', () => {
630646

631647
test('does not fail when attempting to abort a canceled promise', async () => {
632648
const asyncPayloadCreator = jest.fn(async (x: typeof arg) => {
633-
await new Promise((resolve) => setTimeout(resolve, 2000))
649+
await delay(200)
634650
return 10
635651
})
636652

0 commit comments

Comments
 (0)