Debarshi Bhattacharjee
Debarshi Bhattacharjee

Reputation: 830

Reuse Redux-Saga Logic/function across components

I'm working on a project that involves multiple saga and reducers. Some of the saga used, are similar, I want to re-use their logic across various components.

Current implementation:


function* fetchUpComingMovies() {
  try {
    const res = yield call(getUpComingMovies);
    const { status, data } = res;

    if (status === 200 && data) {
      yield put(successGetUpComingMovies(res.data.results));
    }
  } catch (error) {
    yield put(failureGetUpComingMovies(error?.message));
  }
}

function* fetchCurrentShows() {
  try {
    const res = yield call(getOnTheAirShows);
    const { status, data } = res;
    if (status === 200 && data) {
      yield put(successGetCurrentShows(res.data.results));
    }
  } catch (error) {
    yield put(failureGetCurrentShows(error?.message));
  }
}

function* fetchTopRated({ payload }) {
  try {
    const res = yield call(getTopRated, payload);
    const { status, data } = res;

    if (status === 200 && data) {
      yield put(successGetTopRated(res.data.results));
    }
  } catch (error) {
    yield put(failureGetTopRated(error?.message));
  }
}


export default function* rootSaga() { 
 yield all([
    takeLatest(homeActionTypes.REQUEST_GET_UPCOMING_MOVIES, fetchUpComingMovies),
    takeLatest(homeActionTypes.REQUEST_GET_SHOWS, fetchCurrentShows),
   takeLatest(homeActionTypes.REQUEST_GET_TOP_RATED, fetchTopRated),
  ]);}

As you can see, the code inside the try/catch block is similar, just the corresponding actions are different. There are more such sagas in other components. I feel like I'm repeating the code and want to re-use the functionality across components. How to solve this issue?

Any help would be appreciated. Thanks

Upvotes: 0

Views: 303

Answers (1)

Lin Du
Lin Du

Reputation: 102367

You can use a saga factory to produce the sagas.

import { call, put, all, takeLatest } from 'redux-saga/effects';
// api
const getUpComingMovies = () => [];
const getOnTheAirShows = () => [];
// action creator
const successGetUpComingMovies = (payload) => ({ type: 'SUCCESS_GET_UP_COMING_MOVIES', payload });
const failureGetUpComingMovies = (payload) => ({ type: 'FAILURE_GET_UP_COMING_MOVIES', payload });
const successGetCurrentShows = (payload) => ({ type: 'SUCCESS_GET_CURRENT_SHOWS', payload });
const failureGetCurrentShows = (payload) => ({ type: 'FAILURE_GET_CURRENT_SHOWS', payload });

function sagaFactory(opts) {
  return function* saga(...args) {
    try {
      const res = yield call(opts.api, ...args);
      const { status, data } = res;

      if (status === 200 && data) {
        yield put(opts.successActionCreator(res.data.results));
      }
    } catch (error) {
      yield put(opts.failureActionCreator(error?.message));
    }
  };
}

export default function* rootSaga() {
  yield all([
    takeLatest(
      'REQUEST_GET_UPCOMING_MOVIES',
      sagaFactory({
        api: getUpComingMovies,
        successActionCreator: successGetUpComingMovies,
        failureActionCreator: failureGetUpComingMovies,
      }),
    ),
    takeLatest(
      'REQUEST_GET_SHOWS',
      sagaFactory({
        api: getOnTheAirShows,
        successActionCreator: successGetCurrentShows,
        failureActionCreator: failureGetCurrentShows,
      }),
    ),
  ]);
}

Upvotes: 1

Related Questions