Na semana passada, respondi a uma pergunta do RxJS em que entrei em uma discussão com outro membro da comunidade sobre: "Devo criar uma assinatura para cada efeito colateral específico ou devo tentar minimizar as assinaturas em geral?" Quero saber qual metodologia usar em termos de uma abordagem de aplicativo totalmente reativo ou quando mudar de um para outro. Isso ajudará a mim e talvez a outros a evitar discussões não-cesarianas.
Informações de configuração
- Todos os exemplos estão em TypeScript
- Para um melhor foco na questão, não é necessário usar ciclos de vida / construtores para assinaturas e manter a estrutura independente
- Imagine: As assinaturas são adicionadas no construtor / ciclo de vida init
- Imagine: O cancelamento da inscrição é feito na destruição do ciclo de vida
O que é um efeito colateral (amostra angular)
- Atualização / entrada na interface do usuário (por exemplo
value$ | async
) - Saída / montante de um componente (por exemplo
@Output event = event$
) - Interação entre diferentes serviços em diferentes hierarquias
Exemplo de uso:
- Duas funções:
foo: () => void; bar: (arg: any) => void
- Duas fontes observáveis:
http$: Observable<any>; click$: Observable<void>
foo
é chamado depois dehttp$
emitido e não precisa de valorbar
é chamado apósclick$
emissão, mas precisa do valor atual dehttp$
Caso: crie uma assinatura para cada efeito colateral específico
const foo$ = http$.pipe(
mapTo(void 0)
);
const bar$ = http$.pipe(
switchMap(httpValue => click$.pipe(
mapTo(httpValue)
)
);
foo$.subscribe(foo);
bar$.subscribe(bar);
Caso: Minimizar assinaturas em geral
http$.pipe(
tap(() => foo()),
switchMap(httpValue => click$.pipe(
mapTo(httpValue )
)
).subscribe(bar);
Minha própria opinião em suma
Compreendo o fato de que as assinaturas tornam as paisagens do Rx mais complexas no início, porque você precisa pensar em como os assinantes devem afetar o canal ou não, por exemplo (compartilhe o que você observa ou não). Porém, quanto mais você separa seu código (mais se concentra: o que acontece quando), mais fácil é manter (testar, depurar, atualizar) seu código no futuro. Com isso em mente, eu sempre crio uma única fonte observável e uma única assinatura para qualquer efeito colateral no meu código. Se dois ou mais efeitos colaterais que eu tenho são acionados pela mesma fonte observável, compartilhamos meu observável e assino cada efeito colateral individualmente, porque ele pode ter ciclos de vida diferentes.
fonte
takeUntil
combinada com uma função chamada dengOnDestroy
. É um um forro que adiciona este ao tubo:takeUntil(componentDestroyed(this))
. stackoverflow.com/a/60223749/5367916se a otimização de assinaturas é o seu fim de jogo, por que não ir ao extremo lógico e seguir este padrão geral:
A execução exclusiva de efeitos colaterais ao tocar e ativar com mesclagem significa que você só tem uma assinatura.
Uma razão para não fazer isso é que você está castrando muito do que torna o RxJS útil. Qual é a capacidade de compor fluxos observáveis e assinar / cancelar a assinatura dos fluxos, conforme necessário.
Eu diria que seus observáveis devem ser compostos logicamente e não poluídos ou confusos em nome da redução de assinaturas. O efeito foo deve ser logicamente associado ao efeito bar? Um precisa do outro? Será que algum dia eu não vou querer ativar gatilho quando o http $ for emitido? Estou criando acoplamentos desnecessários entre funções não relacionadas? Todas essas são razões para evitar colocá-las em um fluxo.
Isso nem sequer considera a manipulação de erros, que é mais fácil de gerenciar com várias assinaturas IMO
fonte