Redux-Saga is a middleware library used to allow a Redux store to asynchronously interact with resources outside of itself.
Redux-Saga helps in:
These types of operations are known as side-effects in Redux-Saga.
A saga is written as a function and implemented as a generator function that yields an object to saga middleware.
You need to use the Redux-Saga middleware to connect to the Redux store.
import { createStore, applyMiddleware } from 'redux';
import createSagaMiddleware from 'redux-saga';
import reducer from './reducers';
import helloSaga from './sagas';
// 1. Create the saga middleware
const sagaMiddleware = createSagaMiddleware();
// 2. Pass it as a middleware while creating the store
const store = createStore(
reducer,
applyMiddleware(sagaMiddleware)
);
// Then run the saga
sagaMiddleware.run(helloSaga);
// sagas.js
// A `hello world` example:
export function* helloSaga() {
console.log("Hello Sagas!");
}
// Async example:
// the asyncSaga Saga sleeps for 1 second via the call to timeout(1000), then dispatches an INCREMENT action(via `put` effect).
export function* asyncSaga() {
yield timeout(1000); // setTimeout is used to implement timeout
yield put({ type: 'INCREMENT' });
}
In this example, we define two sagas (functions). One of them is a very simple HelloWorld
program, and the other is an async
saga.
In the async
saga, we write the following:
yield timeout(1000)
It is a simple statement that calls an async function (setTimeout
in this case), and execution is suspended until it resolves.
After that, control goes to the next statement:
yield put({ type: 'INCREMENT' })
This statement yields an object to the saga middleware and tells it to dispatch an INCREMENT
action.
put
is the magical word here, which is also known as an effect in redux-saga.
Effects are plain JavaScript objects that contain instructions to be fulfilled by the middleware.
They can be imported from redux-saga/effects
.
There are various types of effects:
put
is one example of what we call an effect, which dispatches an action to the store.put({type: 'INCREMENT'}) // => { PUT: {type: 'INCREMENT'} }
call
will call the given function.call(timeout, 1000) // => { CALL: {fn: timeout, args: [1000]}}
You could also call the timeout
function normally (timeout(1000)
) without using the call
effect, but then you won’t be able to write the unit test cases for your saga properly.
Apart from the effects, there is a helper function that is required to write a basic saga.
takeEvery
, a helper function provided by Redux-Saga, listens for dispatched actions (SOME_ACTION
) and runs takeSomeAction
each time.function* watchSomeAction() {
yield takeEvery('SOME_ACTION', takeSomeAction)
}
takeEvery
is a way to tell Redux-Saga that you need to listen to this action and, whenever that is dispatched from a component, call takeSomeAction
.
Below is a flow diagram for a basic Redux-Saga flow.
According to this diagram:
takeEvery()
helper function.Here is the link to the demo for you to play around with this example. Make sure to read the README.md
file first.