Skip to main content

What does redux-thunk do?

Short answer

redux-thunk is 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:

javascript
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:

javascript
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:

javascript
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:

javascript
store.dispatch(fetchUser(5))

What happens:

  1. Redux Thunk sees that the action is a function.
  2. It calls it, passing dispatch and getState.
  3. The function makes the request.
  4. When the data arrives, it dispatches ordinary actions itself (USER_FETCH_SUCCESS).

Under the hood (redux-thunk in 5 lines)

javascript
const thunkMiddleware = store => next => action => { if (typeof action === 'function') { return action(store.dispatch, store.getState) } return next(action) }

The mechanism:

  • If action is 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():

javascript
const store = configureStore({ reducer: rootReducer, })

You can immediately use asynchronous actions through:

  • createAsyncThunk() (the recommended way)
  • or write your own thunk functions by hand.

Example with RTK createAsyncThunk

Redux Toolkit does the same thing, but simpler:

javascript
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/pending
  • user/fetch/fulfilled
  • user/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

javascript
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 doesDescription
redux-thunkMiddleware that lets you dispatch functions
Main goalAsynchronous actions (API, timers, side effects)
What a thunk receivesdispatch, getState
When it is usedWhen loading data, logging in, delays, and so on
In RTKAlready built into configureStore()

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.