In this article we will try to understand the concept of redux-saga. I’m using Redux-saga in my react-redux apps since last two years and will share my experience with saga.
Introduction
Redux-saga is a middleware library which basically used used in redux flow of the application.To manage the complexity of redux application and to manage the potential errors.
The basis purpose of the Redux-saga is to easily manage the application side effects and better handling of failures. The side effects could be asynchronous things like data fetching and action dispatches etc.
To handle asynchronicity in our app, previously we were using redux-thunk which is a simple approach while redux-saga is a full-featured libraries.
Redux-saga uses the ES6 feature called generators function*
to get all its functionality.
Using Redux-saga
To use redux-saga in your app, first we have to add the library to our project. lets suppose we are using react with redux and npm as package manager than, we can install redux-saga with script npm install --save redux-saga
Before using saga in our app, we have to create a watcher
and connect it to our store.
Saga.js(watcher)
import { takeEvery } from './actions';
/*
the 'watcher' - on every 'GET_DATA_REQUEST' action, run our actions functions (side effect or generators)
*/
export default function* sagaWatcher() {
yield takeEvery(API_BUTTON_CLICK, apiSideEffect);
…
}
Our watcher is ready, now we will connect it to the store in store.js
.
store.js
import createSagaMiddleware from 'redux-saga'
import reducer from './reducers'
import sagaWatcher from './Saga'
// create the saga middleware
const sagaMiddleware = createSagaMiddleware()
// mount it on the Store
const store = createStore(
reducer,
applyMiddleware(sagaMiddleware)
)
// then run the saga and connect the saga watcher function to this store
sagaMiddleware.run(sagaWatcher)
This watcher will consistently watch the actions dispatched and if any action type matched to the watcher’s listed action types, it will trigger the respective side effects( async functions).
Now we can use redux-saga in our app. To do so lets suppose we have a button in react component, by clicking this button we need to call an API to get data from the server and response will be stored to the reducer. To complete this whole process we have some action types
i.e.
GET_DATA_REQUEST,
GET_DATA_SUCCESS,
GET_DATA_FAILED.
When we click on the button, an action of type GET_DATA_REQUEST
would be dispatched.
…
handleButtonClick() {
const { token, dispatch } = this.props
dispatch({type: 'GET_DATA_REQUEST', payload: {token}})
}
…
}
Saga watcher from Saga.js
will get this action dispatched and try to match action type GET_DATA_REQUEST
. Since this action type is listed in saga watcher, it will trigger the corresponding side effect (or async generator function or action function from acrions.js)
actions.js
import { fireAjax } from './api';
export function* apiSideEffect(action) {
try {
const data = yield call(fireAjax, action.payload);
yield put({ type: GET_DATA_SUCCESS, payload: data });
} catch (e) {
yield put({ type: GET_DATA_FAILED, payload: e.message });
}
}
Here as we get the response from the api, it could be success or failure. Based on the response we are dispatching the GET_DATA_SUCCESS
or GET_DATA_FAILED
to pass data to the reducer.
NOTE: Instead of calling dispatch in our thunk example, we now call put (we can think of these as equivalent).
We have successfully implemented and integrated Redux-Saga to our React-redux app, and also completed the flow of an action.
Each flow of action follow the below steps…
-
The action GET_DATA_REQUEST is dispatched.
-
The watcher saga (Saga.js) takes the dispatched action and calls the apiSideEffect (from actions.js).
-
The API call is executed.
-
An action to update the reducer is dispatched (success or fail)
Why should we use Redux-saga?
Above is the same process as Redux-thunk but the code looks different.
-
Instead of
dispatch
in thunk, here we haveput
in saga. -
In saga we have `watcher` function which triggers the action functions.
-
We uses
call
effect to call an endpoint and get data as response.
…
There’s a big range of APIs which empowers redux-saga and makes it more usable and easy to manage. Its really very easy to integrate to our app and its flow and structure gives a better shape to the app.
I’m convinced to use it if the app is big and complex.
Full Example
(Need to update below example)
Conclusion
In this blog, I mentioned how to implement an asynchronous operation in Redux with Redux-saga. I left action creators to prevent complexity in above examples.
There no way for handling side-effects in redux. so we have to use middleware i.e. Redux-thunk, redux-saga etc. When choosing one of them we should look into the complexity of the app. If its really a complex app I recommend Redux-saga since its very easy to manage.