Skip to content

Commit 250d34a

Browse files
committed
doc examples for cancellation
1 parent 335275f commit 250d34a

File tree

1 file changed

+80
-1
lines changed

1 file changed

+80
-1
lines changed

docs/api/createAsyncThunk.md

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,6 @@ interface RejectedAction<ThunkArg> {
133133
requestId: string
134134
arg: ThunkArg
135135
aborted: boolean
136-
abortReason?: string
137136
}
138137
}
139138

@@ -278,3 +277,83 @@ const UsersComponent = () => {
278277
// render UI here
279278
}
280279
```
280+
281+
## Cancellation
282+
283+
If you want to cancel your running thunk before it has finished, you can use the `abort` method of the promise returned by `dispatch(fetchUserById(userId))`.
284+
285+
A real-life example of that would look like this:
286+
287+
```ts
288+
function MyComponent(props: { userId: string }) {
289+
React.useEffect(() => {
290+
const promise = dispatch(fetchUserById(props.userId))
291+
return () => {
292+
promise.abort()
293+
}
294+
})
295+
}
296+
```
297+
298+
After a thunk has been cancelled this way, it will dispatch (and return) a `thunkName/rejected` action with an `AbortError` on the `error` property. The thunk will not dispatch any further actions.
299+
300+
Additionally, your `payloadCreator` can use the `AbortSignal` it is passed via `thunkApi.signal` to actually cancel a costly asynchronous action.
301+
302+
The `fetch` api of modern browsers aleady comes with support for an `AbortSignal`:
303+
304+
```ts
305+
const fetchUserById = createAsyncThunk(
306+
'users/fetchById',
307+
async (userId, thunkAPI) => {
308+
const response = await fetch(`https://reqres.in/api/users/${userId}`, {
309+
signal: thunkAPI.signal
310+
})
311+
return await response.json()
312+
}
313+
)
314+
```
315+
316+
But of course, you can also use it manually.
317+
318+
### using `signal.aborted`
319+
320+
You can use the `signal.aborted` property to regularly check if the thunk has been aborted and in that case stop costly long-running work:
321+
322+
```ts
323+
const readStream = createAsyncThunk('readStream', async (stream: ReadableStream, {signal}) => {
324+
const reader = stream.getReader();
325+
326+
let done = false;
327+
let result = "";
328+
329+
while (!done) {
330+
if (signal.aborted) {
331+
throw new Error("stop the work, this has been aborted!");
332+
}
333+
const read = await reader.read();
334+
result += read.value;
335+
done = read.done;
336+
}
337+
return result;
338+
}
339+
```
340+
341+
### using `signal.addEventListener('abort', () => ...)`
342+
343+
```ts
344+
const readStream = createAsyncThunk(
345+
'readStream',
346+
(arg, { signal }) =>
347+
new Promise((resolve, reject) => {
348+
signal.addEventListener('abort', () => {
349+
reject(new DOMException('Was aborted while running', 'AbortError'))
350+
})
351+
352+
startActionA(arg)
353+
.then(startActionB)
354+
.then(startActionC)
355+
.then(startActionD)
356+
.then(resolve)
357+
})
358+
)
359+
```

0 commit comments

Comments
 (0)