Before going to redux-saga, let's address why redux is used. A
complex react app having many components may need to
communicate between components to make some logic work.
React communicates data between components in a
“unidirectional flow” that is from parent to child. For
backflow, we pass data through methods. Even if it's able to
communicate between components it results in “spaghetti code”.
So redux is used as a state management tool with react, in
which the state of your application is kept in a store, and
each component can access any state that it needs from this
store.
Install these packages to use redux in your react-app.
Go through
https://redux.js.org/introduction/getting-started
if you are new to redux as this blog focus on redux-saga
middleware.
In redux when an action is dispatched, the new state is
computed and saved, but something like logging, asynchronous
API calls, etc. in between may be required. That’s where
middleware will help us. It provides a third-party extension
point between dispatching an action, and the moment it reaches
the reducer.
There are middlewares such as redux-thunk, here we will
discuss redux-saga.
Use the this command to add redux-saga to your node
application.
-
npm install --save redux-saga
In the first step, create middleware using
createSagaMiddleware method exported by redux-saga which
creates middleware from a saga, where saga is basically a
generator function.
createStore has reducer, [preloadedState], [enhancer] as
arguments. Redux has an enhancer applyMiddleware which can
take multiple middlewares as arguments, but here, only the
sagaMiddleware is applied. Use the
sagaMiddleware.run(rootSaga) to start our Saga. In the above
example, middleware log “Hello Sagas!” into the console
every time an action is dispatched.
To make middleware work based on dispatched action, use
effect creators from redux-saga/effects. Effect creators
return a plain JavaScript object and do not perform any
execution. The execution is performed by the middleware
during the iteration process of the generator function. The
middleware examines each Effect description and performs the
corresponding action. Redux-saga provides many effect
creators, now let us discuss put and takeEvery effect
creators.
Here incrementAsync saga is used to add 1000ms delay to
dispatching action of type 'INCREMENT'.
Here yield keyword has nothing to do with redux-saga, it is
a basic JavaScript concept. The yield pauses generator
function execution and the value of the expression following
the yield keyword is returned to the generator's caller. It
can be thought of as a generator-based version of the return
keyword. incrementAsync Saga is suspended until the promise
is resolved by delay. Once the promise is resolved,
middleware will resume saga to resolve the next yield. Next
yield is put effect that instructs the middleware to
dispatch an action to the store. In this example, action
INCREMENT.
Next, watchIncrementAsync saga uses takeEvery(pattern, saga,
...args) effect which is a helper function that spawns a
saga on each action dispatched to the store that matches the
pattern. In the above example, it listens for dispatched
INCREMENT_ASYNC actions and run incrementAsync each time.
There are many other effect creators like takeLatest, fork,
call, etc. Refer redux-saga docs to learn more about them.
Back to the quiz app, it needs to do an asynchronous API
call to get the category list. Use a similar approach for
that.
Here is a function fetchCategories that makes an API call
using axios.
In the fetchCategoryData saga call effect return promise as
result. This result is passed to put effect as action data.
Finally, rootSaga that contains takeEvery effect listens for
dispatched GET_CATEGORY_LIST actions and runs
fetchCategoryData each time.
So, whenever a GET_CATEGORY_LIST action dispatches saga
middleware will run fetchCategoryData saga and pass data
from API call to GET_CATEGORIES action to update the state.