Как выполнить побочный эффект внутри эпоса в редукционно-наблюдаемом?

В redux-observable эпики принимают поток действий и возвращают новый поток действий. В моем случае использования мне нужно отправить событие аналитики после того, как какое-то действие было отправлено, и после этого ничего не делать.

С redux-saga я могу просто прослушать это действие с помощью takeEvery и выполнить побочный эффект внутри функции саги:

function* saga() {
  yield takeEvery('SOME_ACTION', function*() {
    sendAnalytics();
  })
}

Но как мне добиться того же с redux-observable? Существует довольно много побочных эффектов, которые не требуют отправки новых действий, таких как инициализация плагинов, ведение журнала, установка файлов cookie и т. д.

Если это антишаблон для обеих этих библиотек, какое решение следует использовать для таких эффектов?


person 1ven    schedule 09.08.2017    source источник
comment
Я не использовал ни redux-saga, ни redux-observable, но я сделал этот конкретный побочный эффект отслеживания, просто вызвав модуль аналитики внутри mapDispatchToProps, что, на мой взгляд, является законным местом для этого. Итак, до или после вызова dispatch вы просто делаете что-то вроде googleAnalytics.trackEvent(...).   -  person timotgl    schedule 09.08.2017
comment
Спасибо, но, на мой взгляд, mapDispatchToProps функции — неподходящее место для реализации побочных эффектов.   -  person 1ven    schedule 10.08.2017


Ответы (1)


Определенно не анти-шаблон, чтобы эпик был «только для чтения», но я хочу предупредить, что часто это признак того, что человек делает что-то менее чем идиоматичное, но это не один из тех случаев.

Вероятно, есть много способов сделать это в Rx. Вот два:

делать + игнорировать элементы

Я думаю, что это наиболее ясное из того, что он делает. do всегда используется только для выполнения побочного эффекта (часто ведения журнала) для следующего/ошибки/завершения, не затрагивая поток. Затем мы используем ignoreElements, чтобы предотвратить повторную отправку SOME_ACTION (что приведет к бесконечной рекурсии). Подробнее об этих операторах см. в документации по rxjs

const someEpic = action$ =>
  action$.ofType('SOME_ACTION')
    .do(() => sendAnalytics())
    .ignoreElements();

Анонимный наблюдаемый

Это несколько более «легкое» решение, поскольку оно не использует никаких операторов, кроме ofType. Я бы предостерег от использования этого, пока вы и ваши товарищи по команде не освоите RxJS и, в частности, создание пользовательских/анонимных Observables. то есть не пишите код, который вы не понимаете.

const someEpic = action$ =>
  new Observable(() =>
    action$.ofType('SOME_ACTION')
      .subscribe(() => sendAnalytics()) // subscription is returned so it can be cleaned up
  );

Этот вариант использования был бы отличным дополнением к разделу «Рецепты» документации, если у кого-то когда-нибудь будет время, чтобы рассказать о нем.


Кстати, это в основном вопрос RxJS, где поток просто является действиями. Возможно, вы обнаружите, что получаете ответы и лучшую долгосрочную поддержку, если будете искать или формулировать свои вопросы в контексте RxJS, а не в контексте избыточного наблюдения. Почти все вопросы, наблюдаемые с помощью редукции, на самом деле являются вопросами RxJS, и это здорово, потому что знания можно передавать!

person jayphelps    schedule 09.08.2017
comment
Я просто хотел бы сказать, что я действительно ценю мысли и усилия, которые вы приложили, чтобы четко и полностью ответить на вопросы, наблюдаемые с помощью редукса, @jayphelps! Я не только изучаю redux-observable, но и ценные советы по RxJS. Тогда спасибо! - person IanVS; 16.11.2017
comment
Почему вы используете ignoreElements вместо НИКОГДА? Какая из них лучше? - person Fen1kz; 10.10.2018
comment
@Fen1kz never() — это статический Observable factory — он возвращает исходный Observable, который никогда не выдает, никогда не завершает и никогда не выдает ошибок. ignoreElements(), с другой стороны, является оператором — это означает, что он работает с другим наблюдаемым источником, а не сам является статическим производителем — что при применении к наблюдаемому просто игнорирует любые значения, которые испускает исходный наблюдаемый. Так что не то же самое :) ignoreElements() НЕ будет игнорировать ошибки/полные. - person jayphelps; 22.10.2018