Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

redux-saga when to use fork?

what would be the difference between the two approaches below?

export function* watchLoginUser() {   yield takeEvery(USER_LOGIN, loginUser) } export function* watchLogoutUser() {   yield takeEvery(USER_LOGOUT, logoutUser) } export function* watchGetParties() {   yield takeEvery(PARTIES_GET, getParties) } export default function* root() {   yield [     fork(watchLoginUser),     fork(watchLogoutUser),     fork(watchGetParties)   ] } 
export default function* root() {   yield [     takeEvery(USER_LOGIN, loginUser),     takeEvery(USER_LOGOUT, logoutUser),     takeEvery(PARTIES_GET, getParties)   ] } 

When do I need to use fork and when not?

like image 480
Guilherme Miranda Avatar asked Mar 21 '17 21:03

Guilherme Miranda


People also ask

When should I use redux saga?

Redux Saga is a middleware library used to allow a Redux store to interact with resources outside of itself asynchronously. This includes making HTTP requests to external services, accessing browser storage, and executing I/O operations. These operations are also known as side effects.

Can we use fork with race?

The fork effect always wins the race immediately. On the other hand, fork effects in a race effect is most likely a bug. In the above code, since fork effects are non-blocking, they will always win the race immediately.

What happens if any of the forked task results in an error?

If any forked task raises an uncaught error, then the parent task will abort with the child Error, and the whole Parent's execution tree (i.e. forked tasks + the main task represented by the parent's body if it's still running) will be cancelled.

Is redux saga deprecated?

Such a powerful & elegant tool as Redux-Saga, a Redux side effect manager, is said to be deprecated, and no longer being maintained, starting from Jan 27, 2021.


2 Answers

In general, fork is useful when a saga needs to start a non-blocking task. Non-blocking here means: the caller starts the task and continues executing without waiting for it to complete.

There is a variety of situations where this can be useful, but the 2 main ones are:

  • grouping sagas by logical domain
  • keeping a reference to a task in order to be able to cancel/join it

Your top-level saga can be an example of the first use-case. You'll likely have something like:

yield fork(authSaga); yield fork(myDomainSpecificSaga); // you could use here something like yield []; // but it wouldn't make any difference here 

Where authSaga will likely include things like:

yield takeEvery(USER_REQUESTED_LOGIN, authenticateUser); yield takeEvery(USER_REQUESTED_LOGOUT, logoutUser); 

You can see that this example is equivalent to what you suggested, calling with fork a saga yielding a takeEvery call. But in practice, you only need to do this for code organisation purposes. takeEvery is itself a forked task, so in most cases, this would be uselessly redundant.

An example of the second use-case would be something like:

yield take(USER_WAS_AUTHENTICATED); const task = yield fork(monitorUserProfileUpdates); yield take(USER_SIGNED_OUT); yield cancel(task); 

You can see in this example that the monitorUserProfileUpdates will execute while the caller saga resumes, and gets to wait to the USER_SIGNED_OUT action to be dispatched. It can in addition keep a reference to it in order to cancel it when needed.

For the sake of completeness, there is another way to start non-blocking calls: spawn. fork and spawn differ in how errors and cancellations bubble from child to parent saga.

like image 89
VonD Avatar answered Oct 12 '22 14:10

VonD


Usually fork become more useful for some cases that has multiple dispatches of API calls, the reason is you can reject the those fetches by instantiating the cancel from the task, e.g. cancel(task1);

Useful if the end-user forcefully exit the application or if one of the tasks was failed that make a problem from your instructions, strategy and logic and it might be reasonable to cancel or terminate the current processing tasks on your saga;

There are 2 ways to cancel the task

base from the documentation of redux-saga Non-Blocking effect cancellation

import { take, put, call, fork, cancel } from 'redux-saga/effects'  // ...  function* loginFlow() {   while (true) {     const {user, password} = yield take('LOGIN_REQUEST')     // Non-Blocking Effect which is the fork     const task = yield fork(authorize, user, password)     const action = yield take(['LOGOUT', 'LOGIN_ERROR'])     if (action.type === 'LOGOUT'){       //cancel the task       yield cancel(task)       yield call(Api.clearItem, 'token')     }   } } 

OR

 import {call, put, fork, delay} from 'redux-saga/effects'; import someAction from 'action/someAction';  function* fetchAll() {   yield fork(fetcher, 'users');   yield fork(fetcher, 'posts');   yield fork(fetcher, 'comments');   yield delay(1500); }  function* fetcher(endpoint) {   const res = yield call(fetchAPI, endpoint);   if (!res.status) {     throw new Error(`Error: ${res.error}`);   }   yield put(someAction({payload: res.payload})); }  function* worker() {   try {     yield call(fetchAll);   } catch (err) {     // handle fetchAll errors   } }  function* watcher() {   yield takeEvery(BLOGS.PUSH, worker); } 

Your welcome :)

like image 33
Maker Avatar answered Oct 12 '22 14:10

Maker