RxJs: получение того, какой из ключей объекта был изменен в последовательности, отфильтрованной с помощью visibleUntilChanged () без сохранения внешнего состояния. - PullRequest
2 голосов
/ 06 июня 2019

Пусть orders$ - последовательность объектов RxJ, как показано ниже. Мы прослушиваем изменения с distinctUntilChanged() и предпринимаем различные действия в зависимости от того, какой ключ был изменен. Можем ли мы сказать внутри tap(), какой ключ объекта фактически изменился, не отслеживая предыдущее изменение с помощью внешней previousItem переменной?

Пример:

let orders$ = of([
  { main: 'pizza', drink: 'cola', id: 0},
  { main: 'pizza', drink: 'cola', id: 1},
    ...
  { main: 'pizza', drink: 'cola', id: 3332},
  { main: 'pizza', drink: 'fanta', id: 3333},    // <-- drink changes
]); 

let previousItem = null;

orders$.pipe(
  distinctUntilChanged((o0, o1) => o0.main === o1.main || o0.drink === o1.drink),
  tap(item => {

      /* Which value actually changed -'main' or 'drink' ?! */

      if (previousItem && previousItem.main !== item.main) {
        doSthForMainChanged();
      }

      doSthForDrinkChanged();
      previousItem = item;        // <-- ... so that not to tweak via external state

  })).subscribe();

Ответы [ 2 ]

2 голосов
/ 06 июня 2019

Я мог бы предложить сделать это с scan:

source$.pipe(
  scan((last: any, item: any) => {
    let changes: any = {}
    last.main !== item.main ? changes.main = true : false
    last.drink !== item.drink ? changes.drink = true : false
    return {item, changes}
  }, {}),
  tap(({item, changes}) => {
    if (changes.main) {
      doSthForMainChanged();
    }
    if (changes.drink) {
      doSthForDrinkChanged();
    }    
  })
)

и при необходимости вы также можете добавить в конце отдельныеUntilChanged

1 голос
/ 06 июня 2019

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

   const main$ = orders$.pipe(
        distinctUntilChanged((o0, o1) => o0.main === o1.main),
        map(value => ({changed:'main', value}))
   );

   const drink$ = orders$.pipe(
        distinctUntilChanged((o0, o1) => o0.drink === o1.drink),
        map(value => ({changed:'drink', value}))
   );

   merge(main$, drink$).pipe(
       tap(item => {
          if (item.changed === 'main') {
              doSthForMainChanged();
          } else if(item.changed === 'drink') {
              doSthForDrinkChanged();
          }
   })).subscribe();

Единственным побочным эффектом вышеперечисленного является то, что нажатие будет выполнено дважды, если и основной напиток, и напиток меняются для одного выделенного значения. Я не знаю, является ли это проблемой для вашей бизнес-логики или нет.

...