Click here to share this article on LinkedIn »

Imagine this saga.js main file, with two functions defined, but a lot more on the way:

import { takeLatest, put, call } from 'redux-saga/effects';

import actions from '../actions';

import api from '../api'; function* getFromServer(params) {

try {

const data = yield call(api.getFromServer, ...params);

yield put({ type: action.GET_FROM_SERVER_SUCCESS, data });

} catch (error) {

yield put({ type: actions.GET_FROM_SERVER_ERROR, error })

}

} function* getOtherStuff(params) {

try {

const data = yield call(api.getOtherStuff, ...params);

yield put({ type: action.GET_OTHER_STUFF_SUCCESS, data });

} catch (error) {

yield put({ type: actions.GET_OTHER_STUFF_ERROR, error })

}

} export function* sagas() {

yield takeLatest(actions.GET_FROM_SERVER, getFromServer);

yield takeLatest(actions.GET_OTHER_STUFF, getOtherStuff);

}

In here, saga takes the latest GET_FROM_SERVER and GET_OTHER_STUFF actions and calls functions from api/index.js, where the actual server communication is decoupled. In this structure, we need three different actions defined in actions/index.js for each endpoint, a new function inside sagas/index.js or a new file and an import. Instead of letting it get big, let’s try to make something generic, like so:

function* generic(...data) {

let func = data[0];

let params = data[1];

let type = params.type;

try {

const data = yield call(api[func], params);

yield put({ type: actions[type] + actions.SUCCESS, data });

} catch (error) {

console.log('saga fail: ', error);

yield put({ type: actions[type] + actions.ERROR, error })

}

} export function* sagas() {

yield takeLatest(actions.GET_FROM_SERVER, generic, 'getFromServer');

yield takeLatest(actions.GET_OTHER_STUFF, generic, 'getOtherStuff');

}

In here, we have a generic api caller we can use for any yield in the main sagas() function. We just need to add one line in the sagas() function and done. Also, in the actions/index.js, we just need to define two suffixes, _SUCCESS and _ERROR, and them use them in saga and redux communication, thus reducing the number of action types.

You can even take it one step further and pass the function name in the dispatch, thus not even having the need to touch saga anymore, but having the communication between a container, api caller and a reducer contained.

If you like the article, gimme some claps and I will post a generic for the api callers too :D