Blog>
Snippets

Replacing Redux Thunk with Redux Saga

Demonstrate the transition from redux-thunk to redux-saga for managing side-effects with complex async logic in Redux 5.0.0.
import { createStore, applyMiddleware } from 'redux';
import createSagaMiddleware from 'redux-saga';
import { put, takeEvery } from 'redux-saga/effects';

// Action Types
const FETCH_DATA = 'FETCH_DATA';
const FETCH_DATA_SUCCESS = 'FETCH_DATA_SUCCESS';
const FETCH_DATA_FAILURE = 'FETCH_DATA_FAILURE';

// Action Creators
export const fetchData = () => ({ type: FETCH_DATA });
export const fetchDataSuccess = (payload) => ({ type: FETCH_DATA_SUCCESS, payload });
export const fetchDataFailure = (error) => ({ type: FETCH_DATA_FAILURE, error });

// Sagas
function* fetchDataSaga(action) {
  try {
    const response = yield call(Api.fetchData, action.payload);
    yield put(fetchDataSuccess(response.data));
  } catch (error) {
    yield put(fetchDataFailure(error));
  }
}

function* watchFetchData() {
  yield takeEvery(FETCH_DATA, fetchDataSaga);
}

const sagaMiddleware = createSagaMiddleware();

// Apply middleware to the store
const store = createStore(
  rootReducer,
  applyMiddleware(sagaMiddleware)
);

sagaMiddleware.run(watchFetchData);
This snippet sets up the Redux store with Saga middleware replacing Thunk. It creates Saga watchers and workers for the fetch data process.
// rootReducer.js
import { combineReducers } from 'redux';

function dataReducer(state = {}, action) {
  switch (action.type) {
    case FETCH_DATA_SUCCESS:
      return { ...state, data: action.payload };
    case FETCH_DATA_FAILURE:
      return { ...state, error: action.error };
    default:
      return state;
  }
}

export const rootReducer = combineReducers({
  data: dataReducer
});
This snippet shows a root reducer that handles actions for fetching data success and failure.
// Api.js
export const Api = {
  fetchData: (payload) => {
    // Replace with your API call
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        if (payload) {
          resolve({ data: 'Sample data' });
        } else {
          reject('Error fetching data');
        }
      }, 1000);
    });
  }
};
This is a mock API module simulating an async data fetching function.
/* styles.css */
.data-container {
  display: flex;
  justify-content: center;
  align-items: center;
}
CSS styles for a container that will display our data.
<!-- index.html -->
<!DOCTYPE html>
<html lang='en'>
<head>
  <meta charset='UTF-8'>
  <meta name='viewport' content='width=device-width, initial-scale=1.0'>
  <title>Redux Saga Example</title>
  <link rel='stylesheet' href='styles.css'>
</head>
<body>
  <div id='app'>
    <div class='data-container'></div>
  </div>
  <script src='path/to/your/compiled/javascript.js'></script>
</body>
</html>
This is the HTML file that includes the CSS and the compiled JavaScript, which will make use of Redux Saga for fetching data and updating the UI.