Orchestrating Long-running Processes with Saga

Illustrate the use of sagas to manage complex, long-running processes such as a file upload progress indicator, using a combination of 'take', 'fork', 'put', and 'cancelled' effects to provide real-time feedback to the user.
import { take, fork, put, call, cancel, cancelled } from 'redux-saga/effects';
import { fileUploadActions } from './actions';
function* uploadFileSaga(action) {
  const { file } = action.payload;
  try {
    const task = yield fork(handleFileUpload, file);
    yield put(fileUploadActions.uploadStart());
    const fileUrl = yield task;
    yield put(fileUploadActions.uploadSuccess(fileUrl));
  } catch (error) {
    yield put(fileUploadActions.uploadFailure(error.toString()));
  } finally {
    if (yield cancelled()) {
      yield put(fileUploadActions.uploadCancelled());
This saga listens for a file upload action, forks a task to handle the upload, and manages the upload state. It updates the state to reflect the start, success, failure, and cancellation of the upload.
import { call } from 'redux-saga/effects';
async function handleFileUpload(file) {
  const formData = new FormData();
  formData.append('file', file);
  const response = await fetch('/upload', { method: 'POST', body: formData });
  if (!response.ok) throw new Error('Upload failed');
  return response.json();
function* watchFileUpload() {
  while (true) {
    const action = yield take(fileUploadActions.uploadRequest().type);
    yield call(uploadFileSaga, action);
Defines the asynchronous file upload handler and a watcher saga. The handler encapsulates the upload logic, while the watcher listens for upload requests and triggers the upload saga.