Redux-Saga for React App — Optimise Your Asynchronous Application
Tags: React, Web Development, Redux Saga, Technology, Redux

React-Redux development is generally fun, but it can become a challenge when there are a lot of asynchronous calls — many questions come in front of you like how do you handle network requests, timeouts, and other callbacks without complicating the Redux actions and reducers?

This blog will give you a brief introduction and will cover some basic concepts related to Redux-Saga and how to start with it.

What’s Redux-Saga?

Redux-Saga is a helper library that allows us to organize all the side effects (i.e. asynchronous things like data fetching and impure things like accessing the browser cache) using ES6 Generators — called “Sagas” and make easier to manage, also is more efficient to execute, simple to test, and better at handling failures.

How does it work?

Sagas are implemented as Generator Functions that yield objects to the Redux-Saga middleware.

So before moving any forward, you need to know what is Generator Function.

To put it simple, Generators are functions that can be paused and resumed, instead of executing all the statements of the function in one pass.

When the Generator Function is invoked, it will return an iterator object. With each call of the iterator next() method, the generator’s body will be executed until the next yield statement and then pause:

Sagas are implemented as Generator functions that yield objects to the Redux-Saga middleware. These yielded objects are kind of instructions that would be passed and interpreted by the middleware.

When a Promise is yielded to the middleware, the middleware will interpret the instruction and would suspend the Saga until the Promise completes and once the Promise is resolved, the middleware will resume the Saga, executing code until the next yield. Thus handling the async actions.

Redux Saga middleware uses Generators behind the scenes, yielding Saga functions or known as Saga Effects like put, all, call, and takeLatest.

The flow would look like this:

– action trigger (a button click dispatches some action)

— saga watcher (specific saga watcher catches the action type)

— async action (do API calls and yield results as a different action type)

— reducer (catch yielded action)

— store update

— render

Let’s understand this with help of an example —

First thing to do is create our Saga middleware and bind it to the Redux store.

So store would look like:

import { createStore, applyMiddleware, compose } from ‘redux’;

import createSagaMiddleware from ‘redux-saga’;

import reducers from ‘redux/reducers’;

import sagas from ‘redux/sagas’;

const sagaMiddleware = createSagaMiddleware();

export function configStore (initialState) {

const composer = compose(applyMiddleware(

sagaMiddleware

));

const store = createStore(reducers, initialState, composer);

sagaMiddleware.run(sagas);

return store;

}

What sample Saga would look like:

import { take, fork, call, put } from ‘redux-saga/effects’;

// The watcher: watch actions and coordinate worker tasks

function* watchFetchDataRequests() {

const action = yield take(‘FETCH_REQUEST’);

yield fork(fetchUrl, action.url);

}

// The worker: perform the requested task

function* fetchUrl(url) {

const data = yield call(fetch, url);

yield put({

type: ‘FETCH_SUCCESS’,

data

});

}

Let’s break it down:

The functions(take, fork, call, put) imported from Redux-Saga/effects are pure functions. As I mentioned, earlier generators yield plain JavaScript objects called effects and these functions serve that purpose.

Instead of actually executing the side effect (i.e. function call) ourselves, by just description of the desired effect is constructed and middleware takes care of the real execution then hands the result back to the generator.

In the above example,

What happens is that the yield take(‘FETCH_REQUEST’) effect will block the watchFetchDataRequests generator until a FETCH_REQUEST action is dispatched. Once we get a matching action, the middleware will resume the generator with the result which is the action object.

The next instruction fork(fetchUrl, action.url) tells the middleware to call a new fetchUrl task with action.url as the argument. Now the middleware will invoke the fetchUrl Generator but without blocking watchFetchDataRequests that means two or more calls can be done at same time. watchFetchDataRequests continues listening to other watchFetchDataRequests actions while the fetchUrl starts doing its work.

watchFetchDataRequests that means two or more calls can be done at same time. watchFetchDataRequests continues listening to other watchFetchDataRequests actions while the fetchUrl starts doing its work. Then, in fetchUrl, we used call(fetch, url) to instruct the middleware to call the fetch function. the middleware will suspend the generator until the Promise returned by fetch is resolved (or rejected) then resume the generator with the resolved value (or throw with the rejected error)

And at last put () tells the middleware to dispatch an action to the Redux store.

Some other Saga effects which can be used are:

Race execute some effects simultaneously if one is done, cancel others.

execute some effects simultaneously if one is done, cancel others. Select invoke in order to get state.

invoke in order to get state. TakeLatest return latest effet’s result.

return latest effet’s result. All make multiple API calls.

So how it is different and better solution?

Key difference and benefits of Sagas:

Declarative style i.e all operations inside Sagas are yielded as plain JavaScript objects, which then get executed by the middleware. This makes easy to organise difficult side effects sequences.

i.e all operations inside Sagas are yielded as plain JavaScript objects, which then get executed by the middleware. This makes easy to organise difficult side effects sequences. The simplicity of testing, i.e. it is easy to test the business logic inside the Saga. You simply test the yielded sequence of objects by a simple deepEqual.

In other solutions, you’ll typically have to mock all the surrounding environment which can make the tests very complicated and less reliable.

Advance async control flow and concurrency management . You can run multiple background tasks in parallel. You can also cancel a running task.

. You can run multiple background tasks in parallel. You can also cancel a running task. Sagas Pattern also brings some structural benefits, since UI components do not typically perform any business logic but only dispatch actions as pure JavaScript objects to notify what happened.

We at Systango have a team of expert coders who all can help you with React-Redux Development. Our wide-sweeping knowledge enables us to work on wide variety projects and deliver brilliant products.

Discuss Your Project Here.

This article was originally published by Systango Technologies, a specialised software studio.