Common Redux Saga Scenarios

Published
Last updated

I've been using redux saga for a while now, and I love the granular control you have over everything. One of the main benefits it has over redux thunk, in my opinion, is how easily you can step through each piece of code when testing. We can literally test every single control flow in the saga at every yield keyword, and determine where the saga should head next. This level of control is worlds apart from the black box that thunks end up becoming.

I mostly use redux saga for handling business logic, since I mostly use react nowadays, it allows me to control more of my data flow with redux, while almost completely removing logic from my presentational components.

Selecting and Dispatching

The put effect is how we dispatch events. If you use react-redux, it's equivalent to use dispatch.

yield put({type: 'ACTION'});
// is the same as...
dispatch({type: 'ACTION'})

Select is another effect which state from the store. It is how you select a piece of the state and it is often used with selectors.

const getUser = (state) => state.user;
const user = yield select(getUser); // Will give the user in the store

Watching Redux Actions

The first example waits for an action to be dispatched, and upon being received, it executes an alert on the window object. This is done with the take effect, and it mostly works like how it sounds - wait to take an action and then proceed. This is a blocking call, meaning following code will not be executed until the action has been taken.

See the Pen Redux Saga take actions example by Neal Fennimore (@nealfennimore) on CodePen.

Fetching Data

Ajax calls are everywhere nowaways and redux saga has a few ways of incorporating them. The first method is call, which like take is also a blocking effect.

Call can be used to run other functions, sagas, or object methods. Object methods need in most cases to set a context so the method can be called directly. That looks like this:

yield call([document.body, 'insertAdjacentText'], 'beforeend', 'Hello');

Which is basically this document.body.insertAdjacentText('beforeend', 'Hello'); without redux sagas syntax.

In this example we're invoking a bunch of calls together in order to fetch my github profile via window.fetch.

See the Pen Redux Saga fetch Github example by Neal Fennimore (@nealfennimore) on CodePen.

Channels for different APIs

Here's an example where we interface with a web worker in order to do some hashing with the sha256 algorithm.

Redux saga gives us an interface through what it calls channels. Channels allow use to subscribe to events from places other than the redux store. We can then take this events and then integrate them however we wish with a saga.

See the Pen Using Web Workers to hash values (sha256) by Neal Fennimore (@nealfennimore) on CodePen.

Conclusion

That's some common scenarios I use redux saga for. It's friendliness to testing and it's ability to handle complex use cases make it a win for me. It beats out similar packages just for these reasons alone. Though it does have a somewhat decent learning curve, mastery of sagas leads to a lot of developer confidence, especially when it is combined with testing.