How Redux Saga Works ?

Redux Saga works as a middleware layer in a Redux Application that intercepts specific dispatched actions to manage complex asynchronous operations and side effects

It acts like a separate background thread that use ES6 Generator Functions (function*) to seamlessly pause, resume and cancel asynchronous operations without blocking the main UI thread.

The Redux Saga Architecture

The entire operational flow relies on three interconnected components moving data through the Redux state ecosystem:

  1. Middleware: Sits between the dispatched action and the reducer. It listens to every action going through the Redux store.
  2. Watcher Sagas: Specialized generator functions that constantly monitor the redux store for specific action types. When a targeted action is found, the watcher triggers a Worker Saga.
  3. Worker Sagas: Generator functions that execute the actual side effects (like handling an API fetch request or localized data manipulation).

UI Component ==> (Dispatches Action) ==> [Redux Saga Middleware] ==>(intercepts & Triggers) ==> [Watcher Saga] ==> (Spawns / Calls) ===> [ Worker Saga – executes API / Side Effects] ==> (yields Result Action) ==> [Reducer – Receives Action] ==> [New State] ==> [UI Component Updates]

Step-by-Step Execution workflow :

To understand how it functions at runtime, follow this sequence:

  1. User Triggers : A user clicks a button in the React UI layer, which dispatches a tracking action like FETCH_USER_REQUEST.
  2. Interception: The Redux Saga Middleware catches this action before it mutates state or reaches the reducer.
  3. Execution: The Watcher Saga detects FETCH_USER_REQUEST and fires off the corresponding Worker Saga.
  4. Suspension (The Generator Magic): The Worker Saga runs until it hits a yield keyword paired with an Effect(Example: yield call(fetchUserApi)). The Saga temporarily pauses here.
  5. Resolution: The middleware executes the asynchronous request under the hood. once the Promise resolves, the middleware automatically wakes up the Saga and passes the resolved data back.
  6. Dispatch: The Worker Saga resumes and dispatches a success or failure outcome action to the Reducers via a put effect (Example: yield put({type: ‘FETCH_SUCCESS’, data}))
  7. State Mutation: The Reducer catches the success action, modifies the application state, and updates the view layer.

Core Redux Saga Effects

Rather than executing functions directly, Sagas use Effects – plain JavaScript objects containing declarative instructions for the middleware to process.

  • takeEvery(): Starts a new worker instance on every matching action dispatched (concurrent requests).
  • takeLatest(): Automatically cancels any previous pending worker instance if a newer version of the same action is fired.
  • call(): Tells the middleware to invoke an asynchronous function. It blocks execution sequentially until the promise resolves.
  • put(): Dispatches an action back to the Redux Store(the saga version of dispatch).
  • select(): Retrieves a slice of data directly from the current Redux store state.

Code Example: Fetching User Profile Data

import { call, put, takeLatest } from 'redux-saga/effects'
import axios from 'axios';
// 1. Worker Saga: Handles the network call logic
function* fetchUserWorker(action) {
try {
// Pauses here until the Axios HTTP request resolves
const response = yield call(axios.get, `https://example.com{action.payload.id}`);
// Dispatches success action to store with fetched payload
yield put({ type: 'USER_FETCH_SUCCESS', user: response.data })
} catch (error) {
// Dispatches error action if API crashes
yield put({ type: 'USER_FETCH_FAILED', message: error.message })
}
}
// 2. Watches Saga: Watches for actions
export function* userWatcherSaga() {
// Intercepts USER_FETCH_REQUESTED and applies takeLatest strategy
yield takeLatest('USER_FETCH_REQUESTED', fetchUserWorker);
}

Why Use Redux Saga over Redux Thunk ?

  • Declarative testing: Because sagas yield plain objects (Effects) rather than executing promises directly. you can easily unit test them step-by-step without mocking API clients or HTTP networks.
  • Advanced execution controls: Sagas make it straightforward to manage complex async orchestrations like race conditions, task cancellations, throttle limits, and background threading.