Reputation: 473
I have a worker saga that consist notifications logic. If response was ok - I push action to my store with data of successful info and then render appropriate message inside my "NotifyMessage" global component. All messages and type of message I receive from store. The same thing I do if response was not ok. After each error/success request I push action to my store with appropriate info. I use delay effect, wait for three seconds and after three seconds I push action to my store to hide my notify message.
The problem is when I try to make one request after another too quickly, there is still delay effect works from previous request. It seems like one message I can see for 2 seconds and another one for 1 second (still previous delay effect do his work). How can I cancel/clear previous delay effect in redux saga generator function (like clearTimeout in setTimeout) when I start a new one?
My sagas pattern is the following:
//Somewhere inside component:
<NotifyMessage alignText="center" type={notifyMsgType}>
{notifyMsg}
</NotifyMessage>
//Store connection inside component
export default connect(
({ notify }) => ({
notifyMsg: notify.message,
notifyMsgType: notify.type,
}),
import {
CREATE_ITEM_FILTER,
DELETE_ITEM_FILTER,
}
from '../../components/manageFilters/actions';
import { createItemFilter } from './manageFilters/createItemFilter';
import { deleteItemFilter } from './manageFilters/deleteItemFilter';
export default function* root() {
yield takeEvery(CREATE_ITEM_FILTER, createItemFilter);
yield takeEvery(DELETE_ITEM_FILTER, deleteItemFilter);
and so on...
}
function* createItemFilter(action) {
try {
if (response.ok) {
const data = yield response.json();
yield put(createItemFilterSuccess(data));
//Update store with appropriate message and type
yield put(showNotifyMessage([`Country ${country} was added to ${region}
region successfully`, 'success']));
//Start timer
yield delay(3000);
//Hide notify message (clear 'message' and 'type' keys in store)
yield put(hideNotifyMessage());
}
} catch (e) {
yield put(showNotifyMessage(['Error occurred during making request', 'error']));
yield delay(3000);
yield put(hideNotifyMessage());
}
}
Upvotes: 0
Views: 2002
Reputation: 473
I've resolved the problem by moving setTimeout to "NotifyMessage" component itself. When new message comes from store - I clear timeout and hide message after 3 seconds. It works as expected. I've totally removed delay effect from my workers sagas. I guess there is a better approach to solve this problem using only worker sagas (race effect and setTimeout?) but for now, everything works as expected.
Upvotes: 2
Reputation: 1568
It works as expected in this sandbox (delay doesn't block other notifications) https://codesandbox.io/s/3q7402mp31
import * as types from './types';
import {
cancelled,
takeEvery,
cancel,
delay,
fork,
take
} from 'redux-saga/effects';
import { toast } from 'react-toastify';
function* notification() {
let notificationId = null;
try {
notificationId = toast(`Notification ⚡`);
yield delay(3000);
toast.dismiss(notificationId);
} catch (e) {
notificationId = yield toast.error(`Error`);
yield delay(3000);
toast.dismiss(notificationId);
// The part of the saga that is triggered after cancel effect occurs
} finally {
if (yield cancelled()) toast.dismiss(notificationId);
}
}
The notifications manager which responsible for cancellation of aborted notifications:
function* notificationManager() {
const notify = yield fork(notification);
yield take(types.SHOW_NOTIFICATION);
yield cancel(notify); // Triggering cancel
}
The watcher saga
export default function* rootSaga() {
yield takeEvery(types.SHOW_NOTIFICATION, notificationManager);
}
Upvotes: 0