Latest news about Bitcoin and all cryptocurrencies. Your daily crypto news habit.
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.
What youâll build
Dog Saga - Redux-Saga Beginner Tutorial
Whatâs redux-saga? Why would I want or need it?
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.
- Read Me · Redux-Saga
- Managing Side Effects In React + Redux Using Sagas
- Redux Saga: The Future is 1975
- Using redux-saga To Simplify Your Growing React Native Codebase
- What is Redux-Saga?
- Redux nowadays : From actions creators to sagas
- Master Complex Redux Workflows with Sagas
Letâs get started
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-saganpm 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.
Redux
Install redux.
npm install --save redux
Create a new file in your src folder called redux.js and add the following code to it.
We have three action types and a single reducer
- 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.
Redux-Saga
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.
- If successful, weâll get a new dog and dispatch API_CALL_SUCCESS along with the dog.
- If a failure, weâll get an 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.
Here are some resources if you want to learn more about generators
Now letâs walk through sagas.js
- a 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 to help avoid too frequent or unnecessary APIÂ calls.
- 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.
- If 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.
- If there was an error with 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.
Hook up React, Redux and Redux-Saga
Ok, we have our pieces, now itâs time to put them all together.
Install react-redux.
npm install --save react-redux
Open your index.js file and make it look like the file below.
The Redux stuff should look familiar.
- createStore with our reducer
- Connect the Redux DevTools to the Store for debugging and learning
- And wrap the <App/> component in a <Provider/> component with the store, which letâs us work with Redux in React.
- Weâll actually 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
Connect <App /> to Redux
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.
- Using 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.
Bring it all together on the screen
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.
Just for fun, letâs cause an error
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!
A recap, step-by-step
- An event takes placeâââe.g. user does something (clicks âRequest a Dogâ button) or an update occurs (like componentDidMount)
- Based on the event, an action is dispatched, likely through a function declared in mapDispatchToProps (e.g.onRequestDog)
- A watcherSaga sees the action and triggers a workerSaga. Use saga helpers to watch for actions differently.
- While the saga is starting, the 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).
- The workerSaga performs some side-effect operation (e.g. fetchDog).
- Based on the result of the 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.
- The 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.
More resources
- Async operations using redux-saga
- This collection of common Redux-saga patterns will make your life easier.
Redux-Saga tutorial for beginners and dog lovers was originally published in Hacker Noon on Medium, where people are continuing the conversation by highlighting and responding to this story.
Disclaimer
The views and opinions expressed in this article are solely those of the authors and do not reflect the views of Bitcoin Insider. Every investment and trading move involves risk - this is especially true for cryptocurrencies given their volatility. We strongly advise our readers to conduct their own research when making a decision.