s_kamianiok
s_kamianiok

Reputation: 473

How to clear previous delay effect when starting a new one in redux-saga

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

Answers (2)

s_kamianiok
s_kamianiok

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

Tomer
Tomer

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

Related Questions