Eu tenho um serviço Angular 2:
import {Storage} from './storage';
import {Injectable} from 'angular2/core';
import {Subject} from 'rxjs/Subject';
@Injectable()
export class SessionStorage extends Storage {
private _isLoggedInSource = new Subject<boolean>();
isLoggedIn = this._isLoggedInSource.asObservable();
constructor() {
super('session');
}
setIsLoggedIn(value: boolean) {
this.setItem('_isLoggedIn', value, () => {
this._isLoggedInSource.next(value);
});
}
}
Tudo funciona muito bem. Mas eu tenho outro componente que não precisa se inscrever, ele só precisa obter o valor atual de isLoggedIn em um determinado momento. Como posso fazer isso?
javascript
angular
rxjs
Baconbeastnz
fonte
fonte
getValue()
é uma enorme bandeira vermelha de que você está fazendo algo errado. Está lá como uma escotilha de fuga. Geralmente tudo o que você faz com o RxJS deve ser declarativo.getValue()
é imperativo. Se você estiver usandogetValue()
, há uma chance de 99,9% de fazer algo errado ou estranho.BehaviorSubject<boolean>(false)
e gostar de alterná-lo?foo$
era umaBehaviorSubject
(ou seja, é definida comoObservable
e talvez seja quente ou fria de uma fonte adiada). No entanto uma vez que, em seguida, ir para o uso.next
em$foo
si que significa que a sua implementação depende de ele ser umBehaviorSubject
modo que não há justificativa para não apenas usando.value
para obter o valor atual em primeiro lugar.A única maneira que você deve estar recebendo valores "fora de" um observável / Assunto é com se inscrever!
Se você estiver usando,
getValue()
estará fazendo algo imperativo no paradigma declarativo. Está lá como uma escotilha de fuga, mas 99,9% do tempo você NÃO deve usargetValue()
. Existem algumas coisas interessantes quegetValue()
farão: Irá gerar um erro se o assunto tiver sido cancelado, impedirá que você obtenha um valor se o assunto estiver morto por estar errado, etc. Mas, novamente, existe como uma fuga eclodem em circunstâncias raras.Existem várias maneiras de obter o valor mais recente de um Assunto ou Observável da maneira "Rx-y":
BehaviorSubject
: Mas realmente assinando . Quando você assina pela primeira vezBehaviorSubject
vez, enviará de forma síncrona o valor anterior que recebeu ou foi inicializado.ReplaySubject(N)
: Isso armazenará em cacheN
valores e reproduzi-las aos novos assinantes.A.withLatestFrom(B)
: Use esse operador para obter o valor mais recente de observávelB
quandoA
emitido. Fornecerá os dois valores em uma matriz[a, b]
.A.combineLatest(B)
: Use este operador para obter os valores mais recentes doA
eB
cada vez que querA
ouB
emite. Fornecerá os dois valores em uma matriz.shareReplay()
: Faz um multicast observável por meio de umReplaySubject
, mas permite repetir o observável por erro. (Basicamente, fornece esse comportamento de armazenamento em cache promissor).publishReplay()
,publishBehavior(initialValue)
,multicast(subject: BehaviorSubject | ReplaySubject)
, Etc: Outros operadores que a alavancagemBehaviorSubject
eReplaySubject
. Diferentes sabores da mesma coisa, eles basicamente fazem multicast da fonte observável, canalizando todas as notificações através de um assunto. Você precisa ligarconnect()
para se inscrever na fonte com o assunto.fonte
click$.mergeMap(() => behaviorSubject.take(1))
para resolver seu problema também.AuthenticationService
que usa umBehaviourSubject
para armazenar o estado atual conectado (boolean
true
oufalse
). Ele expõe umisLoggedIn$
observável para assinantes que desejam saber quando o estado muda. Ele também expõe umaget isLoggedIn()
propriedade, que retorna o estado atual de logon chamandogetValue()
o subjacenteBehaviourSubject
- isso é usado pelo meu guarda de autenticação para verificar o estado atual. Parece-me um uso sensatogetValue()
...?Eu tive uma situação semelhante em que assinantes atrasados assinam o Assunto após a chegada do valor.
Eu encontrei ReplaySubject, que é semelhante ao BehaviorSubject, funciona como um encanto neste caso. E aqui está um link para uma melhor explicação: http://reactivex.io/rxjs/manual/overview.html#replaysubject
fonte
next()
função ainda não foi invocada, enquanto o BehaviourSubject emite. O emitem imediato é muito útil para a aplicação de valores padrão para uma visão, quando o BehaviourSubject é usado como fonte de dados observáveis em um serviço, por exemploVocê pode conferir o artigo completo sobre como implementá-lo aqui. https://www.imkrish.com/how-to-get-current-value-of-observable-in-a-clean-way/
fonte
Encontrei o mesmo problema em componentes filhos, nos quais, inicialmente, ele teria que ter o valor atual do Assunto, depois me inscrevi no Assunto para ouvir as alterações. Eu apenas mantenho o valor atual no Serviço para que ele esteja disponível para acesso aos componentes, por exemplo:
Um componente que precisa do valor atual pode acessá-lo a partir do serviço, ou seja:
Não tenho certeza se esta é a prática correta :)
fonte
async
pipe.Um semelhante à procura resposta foi downvoted. Mas acho que posso justificar o que estou sugerindo aqui para casos limitados.
Embora seja verdade que um observável não tenha um valor atual , muitas vezes ele terá um valor imediatamente disponível . Por exemplo, nos repositórios redux / flux / akita, você pode solicitar dados de um repositório central, com base em vários observáveis e esse valor geralmente estará disponível imediatamente.
Se for esse o caso, quando você
subscribe
o valor voltará imediatamente.Então, digamos que você tenha telefonado para um serviço e, ao concluir, deseja obter o valor mais recente de algo da sua loja, que potencialmente não seja emitido :
Você pode tentar fazer isso (e manter o máximo possível as coisas 'dentro dos tubos'):
O problema é que ele será bloqueado até que o observável secundário emita um valor, o que potencialmente nunca poderia ser.
Recentemente, me vi precisando avaliar um observável apenas se um valor estivesse disponível imediatamente e, mais importante, eu precisava ser capaz de detectar se não estava. Acabei fazendo isso:
Observe que, para todas as opções acima, estou usando
subscribe
para obter o valor (como @Ben discute). Não.value
estou usando uma propriedade, mesmo que eu tivesse umBehaviorSubject
.fonte
Embora possa parecer um exagero, essa é apenas outra solução "possível" para manter o tipo Observable e reduzir o padrão ...
Você sempre pode criar um getter de extensão para obter o valor atual de um Observável.
Para fazer isso, você precisaria estender a
Observable<T>
interface em umglobal.d.ts
arquivo de declaração de digitação. Em seguida, implemente o getter de extensão em umobservable.extension.ts
arquivo e, finalmente, inclua os tipos e o arquivo de extensão no seu aplicativo.Você pode consultar esta Resposta do StackOverflow para saber como incluir as extensões no seu aplicativo Angular.
fonte
Você pode armazenar o último valor emitido separadamente do Observável. Em seguida, leia-o quando necessário.
fonte
A melhor maneira de fazer isso é usar
Behaviur Subject
, aqui está um exemplo:fonte
Uma assinatura pode ser criada e após a destruição do primeiro item emitido. Pipe é uma função que usa um Observable como entrada e retorna outro Observable como saída, sem modificar o primeiro observável. Angular 8.1.0. Pacotes:
"rxjs": "6.5.3"
,"rxjs-observable": "0.0.7"
fonte