Getting Started With Redux-Saga
Learn how to handle side effects in Redux applications using redux-saga, a powerful middleware that leverages JavaScript generators for predictable, testable asynchronous logic.
By Katia Wheeler ·

At some point in your redux development, side effects are going to happen. How you deal with the side effects are imperative to creating an application that is easier to maintain, extend, refactor, debug, and test. There are quite a few side effect handling libraries (redux-thunk, redux-saga, redux-effect, redux-loop, etc.) and there are many pros and cons to each.
For the purpose of this article, we’re going to take a look at setting up redux-saga in your application. I am also using reactwith my sample application, but redux and redux-saga are not exclusive to react.
Benefits of Redux-Saga
Personally, I prefer redux-saga over other asynchronous helper libraries that are available for a few reasons:
First, it makes use of JavaScript’s Generators, which allow us to yield each step of the way. This makes for simple step-by-step execution that is predictable and easy to test.
Secondly, it allows us to wrap our side effect producing actions in a try {} catch {} block, giving us error handling capabilities.
The final reason, and my personal favorite, is that redux-sagasubscribes to our application’s Store and can trigger a saga to run or continue when a certain action is dispatched.
Sagas are able to subscribe to and listen for an action to be dispatched (similarly to a reducer) and then run the Saga based on that action. That’s pretty freakin’ sweet.
Installation
Installing redux-saga is easy. All you need to do is open your terminal/console and run npm install redux-saga or yarn add redux-saga, depending on which package manager you use. This is also assuming that you already have react , redux, and react-reduxinstalled with a Store already configured.
Our Component
In our application, we have a Component called ListOfThings. This Component has a button that when pressed, loads a list of things from an API. It looks like this:
What Actions and Action Types Do We Have?
Our ListOfThings Component has a mapDispatchToProps that dispatches our loadList action. Our actions and action types look like this:
Note that we have a LIST_LOADED and listLoaded action type and action. We will use those later to update our state in a reducer, so ignore them for now.
So What Does a Saga Look Like?
We now need something to listen to our loadList action. We could use a reducer, however, we need to make an API call to receive our list and we need something to help manage our side effects. We’re going to handle the API call and side effects in a Saga.
Our saga.js file will end up looking like this:
What Does This All Mean?
There’s a lot going on here so let’s break this down a bit. Bear with me.
We have two Generator functions here: loadList and watchLoadList. We're going to unpack each separately, as they each have their own purposes.
watchLoadList
watchLoadList is set up similarly to a reducer; it is listening for our LOAD_LIST action type and will kick of the loadList Saga once the action type is received.
There’s some redux-saga specific functions in here so let’s go over them really quick.
takEvery is a function that has a pattern (in our case the action type) that once matched, will spawn a Saga (our loadList Saga in this case).
When we export our Sagas (as seen on line 21) we export our “watch” Generators in an array and fork them. fork starts a non-blocking task in our Saga. fork is used mostly when grouping Sagas of similar logic and also for keeping a reference to a task that might want cancel/join to be called later.
loadList
Our loadList Generator function is the essence of our Saga. Here, we have our API call wrapped in a try {} catch {} which, in this example, will log any error to the console. In a real-world application we’d most likely want to dispatch another action, such as one that shows an error modal. Let’s step through our Saga, similar to how the Generator would handle it.
First, we create a request using call. The call function takes in a function and creates a non-blocking Effect description of what the passed in function is going to do. The function argument of call can be either a Generator function or a “normal” function. In the example above, our apiLoadFakeUserList function looks like this:
The next thing we do is actually make the call and pass in the request that we created above. makeNetworkCall is a wrapper for fetch that has response and error handling baked in. It looks like this:
As long as there are no errors thus far, we can put an action with the response content out there for a listening reducer to update our state. put instructs the Saga Middleware to dispatch an action to the Store. This is a non-blocking Effect and any errors created are boiled down to whatever is listening, which in our case is a reducer. In our example, we dispatch the listLoaded action and pass our responseObject.response.content , which is our list, through to the action.
Our reducer should look like like this:
That Was A Lot. Does It Work Yet?
Phew. Now that we have our saga created and exported, we now need to setup our Saga Middleware in our Store in order for our application to utilize the Saga we created.
In our store.js file, we need to create a root saga that holds all of our applications’ Sagas. Like all of our Sagas, our root Saga is going to be a Generator function. Our root Saga is combines all of our other Sagas using the all function. This rootSaga is what we’ll pass to our Saga Middleware.
In our store.js file, we also need to configure our Store to take in a Middleware for our Sagas. We create our Saga Middleware using the createSagaMiddleware() function that redux-saga provides to us. From here, we pass our sagaMiddleware into a Store using the applyMiddleware function seen below on line 25. Finally, we need to run our Saga Middleware and pass in our rootSaga. Our Store should look something like this:
The End?
That’s it! That’s the basics of implementing redux-sagaand should point you in the right direction for handling side effects in your applications. From here, it gets much easier and all you have to do is add more Sagas and import them into your rootSaga.
There are many different patterns and anti-patterns for configuring your Sagas and Saga Middleware, so this is not the only way to implement it. Try out some news things, create some new Sagas, and see where it takes you!
More information onredux-sagacan be found on theirGitHubordocumentation site.
More where this came from
This story is published in Noteworthy, where thousands come every day to learn about the people & ideas shaping the products we love.
Follow our publication to see more product & design stories featured by the Journal team.
Originally published on Medium.