Entendendo o RxJS: BehaviorSubject

Como funciona o BehaviorSubject?

Entendendo o RxJS: BehaviorSubject

Se você trabalha com a biblioteca reativa RxJS, com certeza já ouviu falar do famoso BehaviorSubject . Mas muitos desenvolvedores ainda tem suas dúvidas de como usar. Alguns até o utilizam, mas não entendem claramente como esse tipo de Subject funciona. Vamos aprender neste artigo. Recomendo ler antes o artigo anterior onde vemos mais sobre o Subject, você pode acessar clicando aqui.

Analogia e exemplos práticos

Poderia muito bem apenas escrever sobre o comportamento padrão do BehaviorSubject simplesmente utilizando as mesmas palavras que a documentação usa e colando um exemplo simples em código, veja a definição:

"Uma variante do Subject que requer um valor inicial e emite seu valor atual sempre que é inscrito. "

É uma explicação bem objetiva. Mas para quem está iniciando, talvez não fique muito claro, principalmente a parte requer um valor inicial e emite seu valor atual sempre que é inscrito. Por isso vamos usar duas analogias que seguem a mesma linha de raciocínio:

Requer um valor inicial:

Imagine que você encontrou um canal no youtube e esse produz conteúdo que te cativa muito, você vai ser a primeira pessoa inscrita nesse canal. O produtor porém está com pouco tempo para organizar e produzir certos conteúdos, então ele deixa um vídeo inicial explicando o porque está ausente e assim que ele voltar com novos vídeos, esse vídeo inicial não será mais necessário. No comportamento padrão do Subject ao clicar no botão de inscrição de um canal, você só receberia uma notificação quando o produtor de conteúdo desse canal postar algum novo vídeo, não existiria um vídeo inicial. Mas o BehaviorSubject necessita de um valor inicial, então ao clicar em subscriber, receberia esse vídeo do produtor de conteúdo referente a inscrição, dizendo que em breve o canal terá novos conteúdos. Nesse caso todos os que se inscreverem irão receber esse vídeo de boas vindas se não existir até o momento um novo vídeo.

Então agora podemos entender que diferente do Subject que não recebe parâmetros em seu construtor, precisamos definir um valor inicial para o Behavior e esse valor inicial é diferente do valor atual!

Vamos agora para a segunda parte e analogia:

Emite seu valor atual sempre que existe um inscrito:

Seguindo a linha de raciocínio do exemplo anterior, imagine que o primeiro inscrito recebe uma notificação de uma atualização no canal, com um novo conteúdo produzido. O primeiro inscrito recebeu até agora nessa história dois vídeos, o primeiro vídeo (valor inicial) e um novo vídeo (valor atual). Mas vamos adicionar um inscrito novo. Esse segundo se inscreveu no mesmo canal e recebe imediatamente uma notificação de uma atualização de um vídeo que foi postado a poucos minutos atrás. Note que ele não recebeu o vídeo inicial, pois não é mais necessário, temos agora um valor atual. O vídeo em questão é o ultimo que foi lançado no canal, é o mais atual. Isso representa bem o comportamento do BehaviorSubject. Quando emite valores, ele apenas envia o ultimo valor gerado.

Não confunda o valor inicial com valor atual. O valor inicia pode ser null, zero ou uma lista vazia. Mas o valor atual é a ultima informação que foi realmente emitida de algum evento.

Mas é obrigatório passar um valor inicial? É importante! Veja em código o que ocorre se não passar:

image.png

No JavaScript provavelmente não vai receber um erro da Intellisense, pois ele passa como undefined como padrão, o que não é nada elegante, mas receberá um erro se estiver usando o TypeScript:

20211210_215353.gif

Vamos ver tudo em código, introduzi pequenos comentários para que fique mais claro:

const behaviorSubject = new BehaviorSubject("Em breve voltamos a produzir conteúdo!"); // Valor Inicial

    // Temos dois novos assinantes no canal do youtube que receberam o valor inicial.

    behaviorSubject.subscribe(d => console.log(`BehaviorSubject inscrito 1:  ${d}`));
    behaviorSubject.subscribe(d => console.log(`BehaviorSubject inscrito 2:  ${d}`));

Resultado no console:

Captura de Tela 2021-12-11 às 09.02.27.png

E se adicionarmos um valor atual? Veja no print:

Captura de Tela 2021-12-11 às 10.53.48.png

Os dois primeiros inscritos tem o valor atual agora. Mas e se um terceiro inscrito entrar em cena quando já foi emitido o valor mais atual? O que ocorre é isto:

Captura de Tela 2021-12-11 às 10.56.41.png

O inscrito três recebeu o ultimo valor! E isso mostra o objetivo do BehaviorSubject, eu não quero emitir valor inicial, apenas o atual para meus inscritos! O operador next() é chamado toda vez que é emitido novos valores. Então nesse caso não seria preciso que o terceiro inscrito, que é um inscrito atrasado, recebesse a primeira mensagem pois o canal já tem seu vídeo mais atual.

Veja outro exemplo em código:

const subject = new BehaviorSubject(123);

// dois novos assinantes obterão valor inicial => output: 123, 123
subject.subscribe(console.log);
subject.subscribe(console.log);

// dois assinantes obterão um novo valor (valor atual) => output: 456, 456
subject.next(456);

// novo assinante (atrasado) receberá o valor mais recente (456) => output: 456
subject.subscribe(console.log);

// todos os três assinantes obterão um novo valor => output: 789, 789, 789
subject.next(789);

Veja o resultado:

image.png

O valor atual é o que manda. É bom sempre se lembrar disso!

Conclusão

Um modo de utilizar bem o BehaviorSubject em nossas aplicações é quando temos que sempre emitir o valor atual para todos os observadores. Isso pode ocorrer quando temos componentes que precisam estar em sincronia com os dados em tela a cada ação do usuário. Um caso que podemos usar é um carrinho de compra de um e-commerce.

Fico por aqui neste artigo, agradeço por ler e qualquer dúvida ou critica construtiva fique à vontade para postar nos comentários 😄.

Referências:

Mastering the Subject: Communication Options in RxJS | Dan Wahlin

Documentação Oficial: RxJS Documentação