RxJS — подпишитесь только один раз, но не завершайте Observable

представьте ситуацию, когда у вас есть некоторый Observable, который содержит данные, которые меняются в реальном времени, пример ниже...

interface User {
   name: string;
   projectId: string;
   dataThatChangesALotInRealTime: Object;
}

userData: Observable<User>

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

<p>
{{ (userData | async)?.dataThatChangesALotInRealTime }}
</p>

Теперь я хочу вставить некоторые данные в базу данных в соответствии с текущими данными в userData наблюдаемых. Вот функция

addToDatabase() {
  let sub = this.userData.subscribe(data => {
     this.exampleDatabase.doc(`test/${data.dataThatChangesALotInRealTime.id}`)
          .add({ test: 'hello'})
     sub.unsubscribe() // <- This
  })
}

Вопрос

Является ли это правильным решением для отказа от подписки внутри подписки, чтобы избежать многократной вставки в базу данных? Есть ли другой/лучший способ сделать это?

Это просто минималистичный пример, если у вас есть какие-то вопросы или мое объяснение плохое, дайте мне знать в комментариях, и я обновлю свой вопрос. Спасибо


person Raold    schedule 09.12.2018    source источник


Ответы (1)


Вы можете использовать оператор first:

this.userData.pipe(first()).subscribe(...);

Это автоматически завершится (и, следовательно, откажется от подписки) после того, как будет отправлено первое значение.

Обратите внимание, что вы должны убедиться, что он излучает хотя бы один раз перед завершением, иначе будет выдана ошибка. Если вы не можете этого гарантировать, вы можете использовать take(1) вместо этого:

this.userData.pipe(take(1)).subscribe(...);

Обратите внимание, что это фактически не изменяет наблюдаемый userData напрямую, поэтому другие подписки на него будут продолжать генерироваться независимо. Это связано с тем, что операторы в rxjs не изменяют наблюдаемые, а вместо этого возвращают новую наблюдаемую.

person Ingo Bürk    schedule 09.12.2018
comment
Я не хочу завершать наблюдаемую userData. я все еще хочу показать данные в компоненте и, возможно, запустить функцию addToDatabase() несколько раз... - person Raold; 09.12.2018
comment
@Raold Это не мешает тебе это делать. Исходный наблюдаемый объект остается нетронутым, поскольку операторы всегда возвращают новый наблюдаемый объект. Таким образом, это не влияет на любые другие подписки на userData. - person Ingo Bürk; 09.12.2018
comment
Если я правильно понимаю, всякий раз, когда я использую оператор pipe, он создает новый наблюдаемый объект? - person Raold; 09.12.2018
comment
Да, rxjs использует неизменность в этом отношении, поэтому добавление оператора не изменяет исходный наблюдаемый объект, а вместо этого возвращает новый. - person Ingo Bürk; 09.12.2018
comment
Спасибо :) Можете ли вы также обновить свой ответ этой информацией? Это поможет другим, кто ищет ответ. - person Raold; 09.12.2018
comment
@ Раолд, я добавил это. Ваше здоровье. - person Ingo Bürk; 09.12.2018