Advanced Redux — Side Effects, Async Tasks & ThunksEntry 4 of 9

What Is a Thunk?

A thunk is a function that delays an action until later. In Redux, it's an action creator that does not return the action itself, but another function that eventually dispatches the action.

Notes

  • Normally dispatch accepts only plain action objects ({ type, payload }).
  • Redux Thunk middleware intercepts dispatched values. If the value is a function, it calls it with dispatch and getState instead of passing it to reducers.
  • Inside that function you can await async work, then dispatch regular actions with the results.
  • configureStore includes the thunk middleware by default. No setup needed with RTK.
  • A thunk is the bridge between async operations and Redux's pure state model.

What / Why / When

What

A function you dispatch instead of an object.

Why

Moves async logic out of components and keeps reducers pure.

When

Async logic is reused, complex, or doesn't belong to any one component.

Code compare

React
// Shape of a thunkconst fetchUsers = () => async (dispatch: AppDispatch, getState: () => RootState) => {  dispatch({ type: "users/loading" });  const response = await fetch("/api/users");  const data = await response.json();  dispatch({ type: "users/success", payload: data });};​// Dispatch it like an actiondispatch(fetchUsers());
React
dispatch(fetchUsers())   │   ▼thunk middleware: "it's a function" → calls it with (dispatch, getState)   │   ▼async work (fetch) → dispatch({ type, payload }) → reducer → new state

NgRx has no thunks. An Effect fills the same role: components dispatch a plain action, the effect listens for it, runs the async work through a service, and dispatches result actions.

No Angular code for this example.

Differences and gotchas

  • A thunk is pulled by the component (dispatch(fetchUsers()) runs the function). An effect is pushed by actions (it listens to the action stream).
  • Thunks run every time they're dispatched. In NgRx, the flattening operator (switchMap, exhaustMap, concatMap) controls overlapping calls.

Quick reference

ConceptReduxNgRx
Async unitThunkEffect
Receivesdispatch, getStateActions stream, injected services
Dispatch resultdispatch(action)Return an action from the stream
Middleware setupBuilt into configureStoreprovideEffects()