React native + Redux-saga

First Redux now saga? What? Why?

Yepp, thats what I thought initially. After exploring further, I started to like how saga played along with my react-redux application. So what is saga? and why saga?

The way I’d like to think of it is, Redux currently handles synchronous actions. That is, you dispatch an action, that updates the reducer. This gets mapped to the store. A direct cycle. But what happens when you dispatch an action, and you expect that action to make an API call, get response, then update the reducer and then get mapped to the store? (Wuttt!) Lets take a look at the picture below.

side effects without saga
  1. In this picture, the child component fires an action to fetch flight names from an api.
  2. There is a method inside the component that does the fetch and dispatchs the action after… Ok so the cycle is complete. Whats wrong with this? Nothing it works perfectly fine… but its not the best way to perform such an action.

If you look at building and managing a bigger app, it becomes a hassle to track and manage all the async actions inside the component. Very hard to ensure reusability and separation of concern. It ends up defeating the whole purpose of having a separate file for actions, for the component rendering and for the handlers. This is when a middleware comes in.

A middleware is sitting beside the components. The middleware was designed keeping in mind that a component should just dispatch the action and not have any concern whatsoever as to what happens after.

Consider the cycle with saga:

side effects with saga

Since the middleware sits separate from the components, its important that these saga files are run in the very start of the app (just like reducers).

const sagaMiddleware = createSagaMiddleware()
const store = createStore(
rootReducer,
applyMiddleware(sagaMiddleware)
);
sagaMiddleware.run(rootSaga)

This wakes up all the sagas that is set up in the rootSaga and makes them listen to relevant actions the action creators call.

The rootSaga has a series of forked saga functions that needs to be included.

import { fork } from ‘redux-saga/effects’;
import { getFlight } from ‘./saga’;
export default function* root_saga() {
yield [
fork(getFlight)
];
}

When an event fires in the child component, then all it has to do is dispatch the action and not worry about what happens after.

//child-component.js
//import action that has the action creator getFlight()
const mapDispatchToProps = (dispatch) => {
return {
onClick: (props) => {
dispatch(getFlight())
}
}
}

The action creator getFlight() has a type: GET_FLIGHT. It is very important that you use the right “type”, because the saga hawk is watching out for that exact “type” to be called. A non coinciding type can result in the wrong or no API call.

Now that the action is dispatched, the saga watching for GET_FLIGHT, kicks off and performs the required async action.

The getFlight() saga is ready to take ‘GET_FLIGHT’ action dispatched from the action creator. Notice how there is a yield before every step, it essentially means the middleware stops/suspends the saga from moving on to the next step until the current step is done.

For Eg: Without yield on step 1, there is no wait for response to come back and update flights. So step 2 would proceed with put, that instructs the middleware to dispatch the action ‘FLIGHTS_LOADED’. Which means, the reducer (below) would update the state for ‘FLIGHT_LOADED’ with null.

Hence it is very essential to insert a yield where you want the middleware to stop the saga from going forward. With yield, once the saga instructs a put with the action and the result, the reducer updates its state. The store now maps the latest states and propagates down the changes to the components. The components then re render and the view is updated.

So if you look at the whole structure, you’ll notice the actions separate, saga(middleware) that takes care of the async action separated and the components clean from all the extra code. This essentially leads us to one of the best coding practice — Decoupling.

And that, concludes the explanation as to why and how saga fits into the whole react-redux ecosystem. Hope you enjoyed and got what you were looking for. :) Feel free to drop your Questions/Comments/Suggestions.