Workshop:

RxJS Avançado para construir interfaces reativas!

William Grasel

@willgmbr

fb.me/wgrasel

define:

reactive programming 

"Reactive programming is a programming paradigm oriented around data flows and the propagation of change."

"Reactive programming is programming with asynchronous data streams"

- André Staltz

O que mais pode ser um Stream?

  • Ações do usuário
  • Eventos de sistema
  • Estado da aplicação
  • Regras de negocio
  • Qualquer fonte de dados ou comportamento, seja síncrono ou assíncrono

Qual a melhor forma de representar um fluxo de dados assíncrono?

síncrono

assíncrono

múltiplo

único

processamento

valor

Objeto

Array

Promise

Observable

Observable

RxJS

The ReactiveX library for JavaScript.


  [1, 2, 3]
    .map(i => i * 2) // [2, 4, 6]
    .filter(i => i > 5) // [6]
    .concat([10, 20, 30]) // [6, 10, 20, 30]

Operators❤️


  Observable.of(1, 2, 3)
    .map(i => i * 2)
    .filter(i => i > 5)
    .concat(
      Observable.of(10, 20, 30)
    )

  Observable.fromEvent(document, 'click')
    .map(i => i * 2)
    .filter(i => i > 5)
    .concat(
      Observable.fromEvent(document, 'blur')
    )

  Observable.from(function* (){ yield 9; })
    .map(i => i * 2)
    .filter(i => i > 5)
    .concat(
      Observable.from([10, 20, 30])
    )
    .subscribe(console.log)

  Array.of(1, 2, 3)
    .map(i => i * 2)
    .filter(i => i > 5)
    .concat(
      Array.of(10, 20, 30)
    )

  Observable.interval(500)
    .map(i => i * 2)
    .filter(i => i > 5)
    .concat(
      Observable.of(10, 20, 30)
    )

  Observable.from(function* (){ yield 9; })
    .map(i => i * 2)
    .filter(i => i > 5)
    .concat(
      Observable.from([10, 20, 30])
    )

Como eu acho o operador que estou precisando?

Marbles Diagrams

Animated Diagrams

Let's code!

Typeahead Search

Reactive Patterns

Imutabilidade!

Cada estado deve fazer parte do fluxo!

NUNCA faça um subscribe dentro de outro!


  @Component()
  export class UserAddressComponent {

    constructor (
      user: UserService,
      address: AddressService,
    ) {
      user.getCurrentUser().subscribe(user => {



      })
    }
    
  }

  @Component()
  export class UserAddressComponent {

    constructor (
      user: UserService,
      address: AddressService,
    ) {
      user.getCurrentUser().pipe(

      ).subscribe(address => {
        this.address = address;
      })
    }
    
  }

  @Component()
  export class UserAddressComponent {

    constructor (
      user: UserService,
      address: AddressService,
    ) {
      user.getCurrentUser().subscribe(user => {
        address.getAddressFromUser(user).subscribe(address => {
          this.address = address;
        })
      })
    }
    
  }

  @Component()
  export class UserAddressComponent {

    constructor (
      user: UserService,
      address: AddressService,
    ) {
      user.getCurrentUser().pipe(
        mergeMap(user => this.address.getAddressFrom(user))
      ).subscribe(address => {
        this.address = address;
      })
    }
    
  }

Nunca esqueça do unsubscribe!

Mas evite fazer isso manualmente!

Use Pipe Async toda vez que o stream for para o template!

Em todas as outras vezes faça unsubscribe reativamente!


  @Component()
  export class MyComponent {

    ngOnInit() {
      interval(1000)
        .subscribe(i => console.log(i));
    }

  }

  @Component()
  export class MyComponent {

    unsubscribe = new Subject();

    ngOnInit() {
      interval(1000)

        .subscribe(i => console.log(i));
    }

    ngOnDestroy() {
      this.unsubscribe.next();
      this.unsubscribe.complete();
    }
    
  }

  @Component()
  export class MyComponent {

    unsubscribe = new Subject();

    ngOnInit() {
      interval(1000)
        .pipe(takeUntil(this.unsubscribe))
        .subscribe(i => console.log(i));
    }

    ngOnDestroy() {
      this.unsubscribe.next();
      this.unsubscribe.complete();
    }
    
  }

Construindo uma Arquitetura Reativa!

O mundo real não é feito apenas de uma fonte de dado

O mundo real tem várias formas de manipular o estado

Vamos subir nos ombros de gigantes!

Capture all changes to an application state as a sequence of events.

FOWLER, Martin. 2005

Modelar a mudança de estados como uma sequencia imutável de eventos

Cada evento descreve apenas a sua mudança para o estado, não o estado atual

O estado atual só pode ser descoberto depois de executar toda a cadeia de eventos!

Alguém consegue citar algum exemplo que implementa esse conceito?

Mas como eu faço isso na prática?

Command Query Responsibility Segregation

FOWLER, Martin. 2011

Um padrão de implementação para Event Sourcing

Visa separar a responsabilidade de quem e de quem escreve

E também separar a
manutenção do estado
dos efeitos colaterais

Let's code!

Simple Counter

Complex Counter

Nós acabamos de recriar o Redux com RxJS puro!

Redux é uma implementação de Event Sourcing e CQRS

Nós podemos chegar no mesmo lugar,

se entendermos o conceito por trás do que usamos!

Mas se você for realmente escalar essa arquitetura para toda sua aplicação, melhor usar uma lib!

NGRX

Mas perai... cadê os efeitos colaterais??

O Redux original não implementa o CQRS completamente...

@ngrx/effects

RxJS powered side effect model

redux-observable

Compose and cancel async actions to create side effects and more.

References

Thanks! =)