One-shot data fetching
A screen needs to load one resource and represent loading, success, and failure in Redux state.
Redux Toolkit · Function
createAsyncThunk generates a thunk for promise-based work and dispatches pending, fulfilled, and rejected actions around it. It leaves state updates to reducers that handle those lifecycle actions.
createAsyncThunk builds a thunk around a payload creator that performs asynchronous work. Dispatching the returned thunk emits pending before the work, then fulfilled or rejected afterward; reducers must decide how to store loading, success, and error state.
createAsyncThunk(typePrefix, payloadCreator, options?)| Name | Type | Description |
|---|---|---|
typePrefix | string | String prefix used to generate the lifecycle action type constants. |
payloadCreator | (arg, thunkAPI) => Promise<Result> | Result | Callback that receives the thunk argument and thunkAPI, and returns a promise or value. |
options | object | Optional configuration for behavior such as conditional execution and serialization. |
A thunk action creator with attached pending, fulfilled, and rejected action creators. Dispatching it returns a promise resolved with the fulfilled or rejected action object.
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'
export const fetchUserById = createAsyncThunk(
'users/fetchById',
async (userId: number, thunkAPI) => {
const response = await fetch(`/api/users/${userId}`, { signal: thunkAPI.signal })
if (!response.ok) throw new Error('Request failed')
return (await response.json()) as { id: number; name: string }
}
)
const usersSlice = createSlice({
name: 'users',
initialState: { status: 'idle', user: null as { id: number; name: string } | null },
reducers: {},
extraReducers: builder => {
builder
.addCase(fetchUserById.pending, state => { state.status = 'loading' })
.addCase(fetchUserById.fulfilled, (state, action) => { state.status = 'succeeded'; state.user = action.payload })
.addCase(fetchUserById.rejected, state => { state.status = 'failed' })
}
})Defines a thunk for the request and handles its generated lifecycle actions in a slice.
A screen needs to load one resource and represent loading, success, and failure in Redux state.
A request should be skipped when existing state already contains suitable data.
The payload creator needs dispatch, state, cancellation, or controlled rejection values while running async logic.
It accepts an action type prefix, a payload creator, and optionally an options object. The prefix is used to form the lifecycle action types.
Follow-up: How are the lifecycle actions produced? The thunk attaches pending, fulfilled, and rejected action creators to the returned thunk action creator.
The thunk dispatches pending before invoking the payload creator. It dispatches fulfilled when the returned promise succeeds and rejected when it fails.
Follow-up: How can a caller handle failure? Await dispatch(...).unwrap(), which turns the rejected result into a thrown error or rejected value.
The payload creator receives the dispatch argument and a thunkAPI object. thunkAPI provides utilities including dispatch, getState, extra, requestId, signal, and rejectWithValue.
Follow-up: How can controlled rejection data reach reducers? Return thunkAPI.rejectWithValue(value) from the payload creator, then handle the rejected action's payload.
createSlicecreateActionthunkAPIrejectWithValueunwrappendingfulfilledrejected