React series — Weather App — Part 6
Hi, in this post I will show how to change our redux middleware from redux-thunk to redux-saga.
The term Sagas in computer science is not new, I won’t explain here but you can read more in this links bellow:
ftp://ftp.cs.princeton.edu/techreports/1987/070.pdf
http://www.cs.cornell.edu/andru/cs711/2002fa/reading/sagas.pdf
https://speakerdeck.com/caitiem20/applying-the-saga-pattern
Let’s talk about the Sagas middleware called redux-saga. It was created by Yassine Elouafi (https://twitter.com/yassineelouafi2) and it is another Redux middleware for handling side effects. It isolates all side effects into “small” artifacts called sagas.
These sagas are implemented using generator functions (mode details here). Unlike normal functions which run to completion and return a value, generator functions can be paused and resumed on demand and can return multiple values.
In redux-saga the action creators never invoke the tasks or functions themselves, instead they always dispatch plain object actions (back to pure functions!) to notify that something happened in the UI and everything else must be encapsulated inside sagas. In order to do that you must create a saga that will watch for the dispatched action and run the desired action.
Ok, let’s get started to change our code to use redux-saga middleware. First we have to install it:
$ npm i redux-saga
Create a new folder sagas and a new file weather_saga.js. After that, do some imports. We are going to use four functions: takeLatest, all, call, put.
takeLatest: Spawns a saga on each action dispatched to the Store that matches pattern. And automatically cancels any previous saga task started previous if it’s still running.
all: Creates an Effect description that instructs the middleware to run multiple Effects in parallel and wait for all of them to complete. It’s quite the corresponding API to standard Promise#all.
put: Creates an Effect description that instructs the middleware to dispatch an action to the Store. This effect is non-blocking and any errors that are thrown downstream (e.g. in a reducer) will not bubble back into the saga.
call: Creates an Effect description that instructs the middleware to call the function
The next step is move the implementation of the action creator to weather_saga.js. Go to index.js on actions folder and change it:
As you can see, the action creator now is a pure function, great! Also we need to change the types:
FETCH_WEATHER_REQUEST: The type our action will dispatch and the saga watcher will be expecting.
FETCH_WEATHER_SUCCESS: The type our saga will dispatch to reducer.
Now all code that access the API need to be moved to our saga weather_saga.js. It should be like this:
The new weather_saga module has three methods:
1 — fetchWeather: the private method that access the api and return a promise;
2 — fetchWeatherSaga: the generator function that will be responsible to resolve the promise and dispatch the real value to reducer;
3 — watcherSagas: the method where we configure what types our sagas should be watching;
Next step is change our reducer to use the new type FETCH_WEATHER_SUCCESS:
And the last step is configure the saga middleware on the root index.js:
I just imported the createSagaMiddleware and watcherSagas. Create the instance of the middleware (line 21), apply this new middleware (line 22) and run the saga watcher (line 24). If you start the application you can see on console the two actions: one for the action creator starting the request and another request success sent by saga to reducer.
The image below explain the basic flow of redux saga:
Like we did with Redux Thunk, let’s talk about pros and cons of redux saga:
Pros
- All the Logic is in one place
- Easy to test
- Built-in support for cancellation
- Supports complex operations
Cons
- Requires generator support (Babel, TypeScript, etc)
- Debugging is not an easy task
That’s all folks! Thanks for reading and if you have some doubts let me know.