Redux Saga
Install
npm install --save redux-saga
About Redux Saga
Is a redux middleware
Consumes and emits actions
Maintains continuously running processes called saga
Used for manage async operations
A long running-background process
Responsible for applications’ side effects
Redux saga is the process manager
How does it works?
Listern for actions and dispatches other actions to who listen for them using Effects
Interact with external APIs or modify system files using Request, Fs or other
Implementation
Add Saga middleware
import createSagaMiddleware from 'redux-saga'
const sagaMiddleware = createSagaMiddleware();
Redux Saga VS Redux Thunk
Use yield and generator function to simplify asyn calls
Redux Saga Effects
Util method provided by Redux Saga
When you invoke an effect it returns an object that contains instructions for Redux Saga
take, takeEvery, takeLatest
wait for a specific kind of action to create a new process
call, fork, spawn
create new processes
take, call
pause the execution of caller process, and others do not
take
Wait for some event
Pause between concurrent lines of code
When the action you specify is dispatched, the code resumes.
le mySaga = function*(){
console.info('Saga begins');
const state = yield effects.take('SET_STATE');
console.info('Got state', state);
}
run(mySaga); //Output: Saga begins
dispatch({type:'SET_STATE', value:42}); //Output: Got state
const { id } = yield take(GET_CURRENT_USER_INFO);
put
Put dispatches an action to the rest of the app
Like calling dispatch in Redux-Thunk or React-Redux
We can use ‘put’ to pass data.
i.e. 1:
// The function that consumes the put
le mySaga = function*(){
console.info('Saga begins');
const state = yield effects.take('SET_STATE');
console.info('Got state', state);
}
run(mySaga); //Output: Saga begins
// Dispatch an action
let putSaga = function*(){
yield effects.put({type:'SET_STATE', value:42})
}
run(putSaga); //Output: Got state
i.e. 2:
yield put(setCurrentUser(data));
##
takeEvery
Instead of taking an action once, it takes every time the specified action is dispatched, and every time it forks a new child process to handle it.
##
takeLatest
Combination of fork, takeEvery, and cancel.
It forks child process each time specified action is dispatched , while keeping exactly one instance of child process running at any time.
When the same action is dispatched , it cancels the previous call and fork a new child to complete the function call.
select
When you yield to the select effect, it returns a copy of the application state.
call
const response = yield call(fetch,`http://localhost:8081/user/${id}`);
fork
Invoke specific method
Caller continues without pausing execution
Finnally block of forked method is invoked during cancellation
//Function fn is forked and the original fn functions continue run
yield effects.fork(fn);
yield items.map(items=>fork(loadItemDetails, item))
spawn
Create a new process.
New process is not the child of caller - will not be cancelled if caller errors or is cancelled.
cancel / cancelled
When you cancel a forked process, stops a forked process.
Stopped process will be cut off at most recent yield.
finally
is invoked in forked process
let process = function*(){
try{
while (true){
yield delay(500)
}
} finally {
console.info('Cancelled?', effects.cancelled() );
}
}
let saga = function*(){
let forked = yield effects.fork(process);
yield delay(5000);
yield effects.cancel(forked);
}
run(saga);
all
Combines numerous take statements into one.
Resumes when all actions have been dispatched.
yield all([
takeLatest(UPDATE_DOOR, updateDoorFromServerSaga),
takeLatest(UPLOAD_MEDIAS, uploadMediasSaga),
]);
also the following works
yield [
takeLatest(UPDATE_DOOR, updateDoorFromServerSaga),
takeLatest(UPLOAD_MEDIAS, uploadMediasSaga),
];
apply
Apply works like call, except it changes the scope of call
const data = yield apply(response, response.json);
call
Calls the specified method, equivalent to invoking the method directly, it is used for testing
const response = yield call(fetch,`http://localhost:8081/user/${id}`);
It creates a promise that resolves after some time.
If you put delay after yield keyword yield will pause the execution of the function for some time.
Effective use of yield
Redux Saga Channels
Action channel
Buffer actions to be processed one at a time
Records all events of a specified type of events or actions
yield actionChannel('UPDATE')
##
Generic channel
Communicate between two sagas
let chan = yield channel();
Event channel
Connects app to outside event sources (Websocket )
Note
A fully-functional shopping cart built with Redux Saga using Yield : https://github.com/danielstern/redux-saga-cart