Отмена наблюдаемой RxJS не работает

У меня есть следующая проблема с некоторой реализацией в React/Redux.

После нажатия на кнопку вызывается определенное действие сокращения, а на экране отображается div с уведомлением. Вы можете закрыть это уведомление, щелкнув знак (X) на этом div (еще одно избыточное действие), или уведомление автоматически закроется через 5 секунд. Нажатие на (x) должно отменить автоматическое действие.

 actions:

const OPEN = 'show_notification';
const CLOSE = 'close_notification';
const CLOSE_AUTO = 'close_auto';

function showNotification(data) {
     return {
        type: 'OPEN',
        data
     }
 }

function closeNotification(index) {
     return {
        type: 'CLOSE',
        index
     }
 }

function closeAuto() {
     return {
        type: 'CLOSE_AUTO'
     }
 }



epics:

import (...)

closeNotificationAuto = action$ => action
.filter(action => action.type === OPEN)
.mergeMap(action => action
.delay(5000)
.map( () => closeAuto)
.takeUntil(action$.ofType(CLOSE))
 }

В любом случае, когда на экране отображаются два уведомления, действие === CLOSE закрывает первое и отменяет задержку() для другого.

Не публикую весь свой код, потому что проблема здесь, в эпиках. Не удается добиться решения:

при нажатии на (x) конкретное уведомление закрывается, но другое (время которого составляет, например, 3 секунды) все еще отображается и автоматически скрывается через еще 2 секунды.

Спасибо за любую помощь!


person Franz    schedule 06.02.2018    source источник


Ответы (1)


Код в эпике неполный, поэтому не совсем понятно (что происходит внутри mergeMap?). Но я заметил одну проблему: ваш takeUntil находится в наблюдаемой цепочке верхнего уровня, что означает, что он не просто отменит эту конкретную задержку, но и вообще перестанет прослушивать какие-либо действия.

Вместо этого вам нужно отложить и отменить совпадающее действие по отдельности внутри чего-то вроде mergeMap, switchMap и т. д. Обычно это называется «изолировать ваши цепочки наблюдателей».

Вот как это может выглядеть:

const closeNotificationAuto = action$ =>
  action$
    .ofType(OPEN)
    .mergeMap(action =>
      Observable.of(action)
        .delay(5000)
        .map(() => closeAuto())
        .takeUntil(action$.ofType(CLOSE))
    );

Этот шаблон, затем фильтрация, а затем flatMap (mergeMap, switchMap и т. д.) — это то, как будет выглядеть большинство ваших эпиков.


Что касается ваших комментариев ниже, похоже, вы хотите добавить фильтр к уведомителю takeUntil, чтобы выполнять только действия CLOSE, которые каким-то образом однозначно идентифицируют его.

См. https://stackoverflow.com/a/48452283/1770633.

const closeNotificationAuto = action$ =>
  action$
    .ofType(OPEN)
    .mergeMap(action =>
      Observable.of(action)
        .delay(5000)
        .map(() => closeAuto())
        .takeUntil(
          action$.ofType(CLOSE).filter(a => a.something === action.something)
        )
    );

Если для каждого из них еще нет уникального идентификатора, вам необходимо создать и включить его.

person jayphelps    schedule 06.02.2018
comment
Спасибо за ответ, но, к сожалению, он все еще не работает. Когда активны два уведомления (первое = 3 секунды на экране, второе = 1 секунда), два потока считают секунды в delay() для каждого уведомления (2 секунды для первого и 4 секунды для второго). Я нажал (x) на первый и вызвал для него действие CLOSE. Первое уведомление скрыто, а функция closeAuto() для этого конкретного уведомления отменяется. Проблема в том, что closeAuto() для второго уведомления также отменяется и никогда не скрывается. Я хочу отменить closeAuto() только для уведомления, которое было нажато (x). - person Franz; 07.02.2018
comment
Спасибо @jayphelps! Работаю как хотел. - person Franz; 09.02.2018
comment
Привет @jayphelps. Я принял ваш ответ - это было очень полезно. Может быть, вы могли бы помочь мне с другим с RxJS? Вот ссылка: stackoverflow.com/questions/48750383/ - person Franz; 12.02.2018