Blog>
Snippets

Redux-Saga for Complex Async Flow

Set up a Redux-Saga to handle side-effects in a complex application, managing multiple asynchronous operations in a clear and maintainable way.
import { takeLatest, call, put, all, fork } from 'redux-saga/effects';
import api from './api';

// Actions
const FETCH_USERS_REQUEST = 'FETCH_USERS_REQUEST';
const FETCH_USERS_SUCCESS = 'FETCH_USERS_SUCCESS';
const FETCH_USERS_FAILURE = 'FETCH_USERS_FAILURE';

// Action Creators
export const fetchUsersRequest = () => ({ type: FETCH_USERS_REQUEST });
const fetchUsersSuccess = users => ({ type: FETCH_USERS_SUCCESS, payload: users });
const fetchUsersFailure = error => ({ type: FETCH_USERS_FAILURE, payload: error });

// Worker Saga: will be fired on FETCH_USERS_REQUEST actions
function* fetchUsers() {
  try {
    const users = yield call(api.fetchUsers);
    yield put(fetchUsersSuccess(users));
  } catch (error) {
    yield put(fetchUsersFailure(error.message));
  }
}

// Watcher Saga: Spawns a new fetchUsers task on each FETCH_USERS_REQUEST
function* watchFetchUsers() {
  yield takeLatest(FETCH_USERS_REQUEST, fetchUsers);
}

// rootSaga combines all the sagas
export default function* rootSaga() {
  yield all([
    fork(watchFetchUsers),
    // Add additional sagas here
  ]);
}
This is a setup for Redux-Saga with rootSaga combining all watcher sagas including watchFetchUsers, which listens for 'FETCH_USERS_REQUEST' action and triggers fetchUsers worker saga to perform API call.
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import createSagaMiddleware from 'redux-saga';
import rootReducer from './reducers';
import rootSaga from './sagas';

// Redux Store Configuration
const sagaMiddleware = createSagaMiddleware();
const store = createStore(
  rootReducer,
  applyMiddleware(sagaMiddleware)
);

// Run the root saga
sagaMiddleware.run(rootSaga);

// React Component
function App() {
  return (
    <Provider store={store}>
      {/* Your App Components */}
    </Provider>
  );
}

export default App;
This is the setup of the Redux store with Saga middleware. It creates the store, applies the sagaMiddleware, and runs the rootSaga to start the Saga processes.
import { useDispatch } from 'react-redux';
import { fetchUsersRequest } from './actions';

function UsersComponent() {
  const dispatch = useDispatch();

  // Dispatch action to fetch users
  const handleClick = () => {
    dispatch(fetchUsersRequest());
  };

  return (
    <div>
      <button onClick={handleClick}>Load Users</button>
      {/* Render users here */}
    </div>
  );
}

export default UsersComponent;
This example component dispatches a fetchUsersRequest action when a button is clicked. That action is caught by the Redux-Saga watchFetchUsers saga.
body {
  background-color: #f3f3f3;
  font-family: 'Arial', sans-serif;
}

button {
  background-color: #4CAF50;
  border: none;
  color: white;
  padding: 15px 32px;
  text-align: center;
  text-decoration: none;
  display: inline-block;
  font-size: 16px;
  margin: 4px 2px;
  cursor: pointer;
  border-radius: 4px;
}

button:hover {
  background-color: #45a049;
}
This is the CSS for styling the UsersComponent, giving app a simple look and feel by setting background color and styles for the button.
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Redux Saga Demo</title>
    <style>
    /* Previos CSS code snippet can be pasted here */
    </style>
</head>
<body>
    <div id="root"></div>
    <script src="path_to_bundled_js_file"></script>
</body>
</html>
The HTML file serves as a container for the React application. It includes a root div where the React components will be mounted, and a reference to the bundled JavaScript file that includes the Redux-Saga logic.