What does redux-thunk do?
Short answer
redux-thunkis middleware for Redux that lets you dispatch not only objects (actions), but also functions (thunks).This is needed to perform asynchronous operations - API requests, timers, side effects, and so on.
The problem without redux-thunk
By default Redux can only handle synchronous actions - plain objects:
store.dispatch({ type: 'LOGIN_SUCCESS', payload: user })But if you need to:
- make a request to the server,
- wait for the response,
- and only then update the store - plain Redux cannot do that.
Redux expects a ready-made action right away, not a process.
What redux-thunk does
redux-thunk intercepts dispatch(action) and checks:
if you passed a function instead of an object, it calls it.
Inside that function you get access to dispatch and getState.
So now you can write asynchronous actions.
Example without Thunk
Not allowed:
store.dispatch(async () => {
const res = await fetch('/api/user')
const data = await res.json()
store.dispatch({ type: 'SET_USER', payload: data })
})Redux will say:
"An action must be an object, and you gave me a function!"
Example with redux-thunk
Allowed:
const fetchUser = (id) => {
return async (dispatch, getState) => {
dispatch({ type: 'USER_FETCH_START' })
const res = await fetch(`/api/users/${id}`)
const data = await res.json()
dispatch({ type: 'USER_FETCH_SUCCESS', payload: data })
}
}And then:
store.dispatch(fetchUser(5))What happens:
- Redux Thunk sees that the action is a function.
- It calls it, passing
dispatchandgetState. - The function makes the request.
- When the data arrives, it dispatches ordinary actions itself (
USER_FETCH_SUCCESS).
Under the hood (redux-thunk in 5 lines)
const thunkMiddleware = store => next => action => {
if (typeof action === 'function') {
return action(store.dispatch, store.getState)
}
return next(action)
}The mechanism:
- If
actionis a function -> call it. - If it is an object -> pass it along the standard Redux flow.
Together with Redux Toolkit
Redux Toolkit already includes redux-thunk by default in configureStore():
const store = configureStore({
reducer: rootReducer,
})You can immediately use asynchronous actions through:
createAsyncThunk()(the recommended way)- or write your own
thunkfunctions by hand.
Example with RTK createAsyncThunk
Redux Toolkit does the same thing, but simpler:
export const fetchUser = createAsyncThunk('user/fetch', async (id) => {
const res = await fetch(`/api/users/${id}`)
return await res.json()
})RTK automatically creates 3 actions:
user/fetch/pendinguser/fetch/fulfilleduser/fetch/rejected
and you just handle them in extraReducers.
When to use redux-thunk
When you need to:
- Make an asynchronous request to an API
- Wait for the result before updating the state
- Get data from the store before an action
- Perform a sequence of
dispatch()calls
Visually
dispatch(fetchUser(5))
│
▼
[redux-thunk checks]
│
├── if it is an object → goes to the reducer
└── if it is a function → calls it with (dispatch, getState)
│
▼
async API request
│
▼
dispatch({ type: 'USER_FETCH_SUCCESS', payload: data })Summary
| What it does | Description |
|---|---|
redux-thunk | Middleware that lets you dispatch functions |
| Main goal | Asynchronous actions (API, timers, side effects) |
| What a thunk receives | dispatch, getState |
| When it is used | When loading data, logging in, delays, and so on |
| In RTK | Already built into configureStore() |
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.