What is Redux-Saga?

Alex Richardson
Universe Engineering
3 min readJun 13, 2017

--

Redux-saga is a redux middleware library, that is designed to make handling side effects in your redux app nice and simple. It achieves this by leveraging an ES6 feature called Generators, allowing us to write asynchronous code that looks synchronous, and is very easy to test.

Before we get any deeper, it’s important to note, that the actual term “saga” has a history in the world of computer science, and isn’t strictly limited to the world of JavaScript. If you’re interested in learning more about Sagas, I recommend checking out this amazing talk by Caitie McCaffrey, titled ‘Applying the Saga Pattern’.

To sum up rather quickly, the Saga pattern is way a to handle long running transactions with side effects or potential failures. For each transaction we wish to complete, we will also need a counter-transaction to revert the original if anything went wrong. Another great resource on this is a blog post by Roman Liutikov called ‘Confusion about Saga pattern’.

Why should we use Sagas?

Now, when creating a new react-redux app, you’ll generally be guided to use redux-thunk or redux-saga to handle asynchronous actions. So why should we use redux-saga?

Well, straight from the docs:

“Contrary to redux thunk, you don’t end up in callback hell, you can test your asynchronous flows easily and your actions stay pure.”

Let’s unpack each of these by comparing a simple example using sagas and thunks. Let’s make an API request to fetch some data on a button click.

Redux Thunk:

Here we have an action creator getDataFromAPI() that would be called from some Button component’s onClick event, which starts our async process:

  • First we fire an action letting our store know that we are about to make an API request ( dispatch(getDataStarted() )
  • Next we actually make the API request, which returns a promise.
  • Then we fire a success action along with our API response or an error action with an error response if anything went wrong.

Redux Saga:

The exact same process, but the code looks a little bit different.

  • Instead of calling dispatch in our thunk example, we now call put (we can think of these as equivalent).
  • We have a ‘watcher’ function that listens to our ‘start’ action. This assumes a Button’s onClick handler would fire a simple redux action with a type API_BUTTON_CLICK
  • We use redux-saga’s call effect, which is a way to get data from any async function (promise, different saga, etc)

Fairly simple, right? On some button click, we’re going to make an API request to some endpoint. If it succeeds we dispatch a new action with our payload. Otherwise we dispatch an error action with an error message.

Right away, it should be noted how much easier it is to read and to understand the saga example. That’s not to say the thunk example is hard to understand, but we can get rid of a few intricacies like returning a function and dealing with a promise chain. Instead we can simply write a try/catch block to catch any errors involved with our network request, and to put (or dispatch) an action to notify our reducers.

Secondly, and arguably most importantly, our Saga side effect function is now pure. This is because the call(getDataFromAPI) doesn’t actually execute the API request, it returns a pure object that looks like this:{ type: 'CALL', func, args } The actual fetch execution is taken care of by the redux-saga middleware, and will return the value back into our generator (hence the yield keyword) or throw an error if there was one.

This is a pretty powerful concept, as we can now test our saga functions with ease. A test for the above snippet would look something like this

Whereas testing the thunk snippet above gets a little trickier. We would have to mock the actual getDataFromAPI call, and any other functions we call inside the thunk. This may not seem like big task, but as our actions grow in complexity, our tests surely will too, which is best to be avoided.

Hopefully this illustrated the three main points of redux-saga to be a little bit clearer. We don’t end up in callback-hell, we keep our actions pure, and our asynchronous flows are easy to test. To learn more, I recommend to check out these resources:

--

--