

I began using redux-saga
at work in a fairly complex boilerplate.
The path to becoming even a little bit comfortable with it was winding and suboptimal, so I thought Iβd write the tutorial I wish Iβd had when just starting out with sagas.
This tutorial assumes you have a solid grasp of React or React Native and Redux. If youβre not ready for redux-saga
(yet), Iβd definitely recommend that you check out this amazing, MASSIVE treasure trove of resources for learning React and Redux.
From the official repo:
redux-saga
is a library that aims to make application side effects (i.e. asynchronous things like data fetching and impure things like accessing the browser cache) easier to manage, more efficient to execute, simple to test, and better at handling failures.
I think of it as an organized way of helping your Redux app communicate and stay in-sync with the outside worldβββmainly external APIs.
Many wonderful people have opined on the pros, cons, and everything else about redux-saga
, much better than I couldβββso here are some links if you want to really nail down the WHATs and WHYs.
Weβll be focusing on the HOW.
Create a new app with create-react-app
.
npx create-react-app dog-saga
Confused by the npx
? So was I, until I read this.
Enter the projectβs directory and fire up the app.
cd dog-saga
npm start
You should now see the boilerplate for create-react-app
, with itβs spinning React logo. Youβll be replacing it with cute dogs soon enough.
Install redux.
npm install --save redux
Create a new file in your src
folder called redux.js
and add the following code to it.
API_CALL_REQUEST
says that weβre beginning the process of fetching
a dog from the Dog API.API_CALL_SUCCESS
tells the Store that we successfully retrieved a dog
and are therefore no longer in the process of fetching
one.API_CALL_FAILURE
tells the Store that something went wrong with our API call. We received an error
rather than a new dog
.But how should we make theAPI_CALL_REQUEST
?
How does the Store know whether the API call was a success or a failure?
HOW DO WE GET PICTURES OF CUTE DOGS DAMNIT??? With a saga.
P.S. Weβre not gonna use action creators in this app. For something so simple, they may muddy the waters. Also, youβll see how redux-saga handles and dispatches actions more clearly (in my opinion) without them.
We want to create a saga, using redux-saga
, that will initiate an API call for a dog image, then tell the Store whether that API call was a success or a failure.
dog
and dispatch API_CALL_SUCCESS
along with the dog
.error
and dispatch API_CALL_FAILURE
along with the error
.Install redux-saga
.
npm install --save redux-saga
Also install axios
, which will help us make Promise
-based API calls.
npm install axios
Create a new file called sagas.js
and add the following code to it.
Before we walk through this new file, notice the function*
syntax. This creates a special kind of function new to ES6 called a generator
.
Generators can pause and restartβββbe exited and re-enteredβββand actually remember the context/state of the function over time.
Each yield
in a generator basically represents an asynchronous step in a more synchronous/sequential processβββsomewhat like await
in an async
function.
redux-saga
relies on generators, but does a decent amount of the work for us, so (in my fairly limited experience) a deep understanding of them for this use-case isnβt necessary.
Now letβs walk through sagas.js
watcherSaga
is a saga that watches for an action to be dispatched to the Store, triggering a workerSaga
.takeLatest
is a helper function provided by redux-saga
that will trigger a new workerSaga
when it sees an API_CALL_REQUEST
, while cancelling any previously triggered workerSaga
still in process.fetchDog
simply uses axios
to request a random dog image from the Dog API and returns a Promise
for the response.workerSaga
attempts to fetchDog
, using another redux-saga
helper function call
, and stores the result (a resolved or failed Promise
) in a response
variable.fetchDog
was a success, we extract the dog
image from the response
and dispatch an API_CALL_SUCCESS
action with dog
in the payload to the Store, using ANOTHER redux-saga
helper function put
.fetchDog
, we let the Store know about it by dispatching an API_CALL_FAILURE
action with the error
.Phew! Itβs a little weird at the beginning, but this pattern/procedure and its benefits become more clear after a few implementations.
Ok, we have our pieces, now itβs time to put them all together.
Install react-redux
.
npm install --save react-redux
Also, install Redux Devtoolsβββmust-have for debugging and seeing Redux (and sagasβ related actions) in action. Go here for info on setting up the Redux dev tools. I recommend using the browser extension.
Open your index.js
file and make it look like the file below.
The Redux stuff should look familiar.
createStore
with our reducer
<App/>
component in a <Provider/>
component with the store
, which letβs us work with Redux in React.connect()
the <App/>
component shortly.To make our redux-saga
work with Reduxβ¦
createSagaMiddleware
, and apply it to the Redux store
with some help from compose
and applyMiddleware
run
the watcherSaga
, so that it can trigger the workerSaga
when thereβs an API_CALL_REQUEST
Open up App.js
and paste the following code into it.
mapStateToProps
to make the most current state of fetching
, dog
and error
available as props
in the App
component.mapDispatchToProps
, we create a function called onRequestDog
that dispatches an API_CALL_REQUEST
action to the Store.connect
the App
component and export this βreduxedβ version of it for use in index.js
.Now letβs walk through some of the changes (top to bottom) made to the App
componentβs rendered output, which allow the user to see the current state of the app and request dog images.
All of these snippets are from the App.js
above, so no new code here.
In the snippet below, we tweaked the image src
to show a dog
image if one exists in the Store. If dog
is null
, it falls back to the React logo
.
If the current state
of our app has a dog
image, we tell the user to keep clicking. If not, we tell them to replace the React logo
with a dog
.
If the current state
has an error, we display some text to let the user know.
Here, if our sagas are currently in the process of fetching
a new dog image, which means workerSaga
has not dispatched an API_CALL_SUCCESS
or API_CALL_FAILURE
yet, we disable the button.
Otherwise, we provide a button for the user to click and request a random dog image.
To see the workerSaga
dispatch an API_CALL_FAILURE
, go into sagas.js
and mess up the url
for the dog api (like changing βbreedsβ to βbedsβ).
Now when you click the βRequest a Dogβ button, the error message displays!
componentDidMount
)action
is dispatched, likely through a function declared in mapDispatchToProps
(e.g.onRequestDog
)watcherSaga
sees the action
and triggers a workerSaga
. Use saga helpers to watch for actions differently.action
also hits a reducer
and updates some piece of state
to indicate that the saga has begun and is in process (e.g. fetching
).workerSaga
performs some side-effect operation (e.g. fetchDog
).workerSaga
βs operation, it dispatches an action
to indicate that result. If successful (API_CALL_SUCCESS
), you might include a payload in the action (e.g. dog
). If an error (API_CALL_FAILURE
), you might send along an error
object for more details on what went wrong.reducer
handles the success or failure action
from the workerSaga
and updates the Store accordingly with any new data, as well as sets the βin processβ indicator (e.g. fetching
) to false.Throughout this process, you can use the updates to Redux state
flowing through to props
to keep your user informed of the process and progress thereof.
Create your free account to unlock your custom reading experience.