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.
npm install redux
npm install react-redux
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 index.js file, a store is created using createStore method and reducer function.
In the above example, a simple reducer is used to manage the categories of a quiz app. There is an action to get categories possibly by an API call.
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.
npm install --save redux-saga
Use the above command to add redux-saga to your node application.
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.
Here incrementAsync saga is used to add 1000ms delay to dispatching action of type '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.
Learn more at https://redux-saga.js.org/.