Programação Reativa para Web na Prática

William Grasel

@willgmbr

fb.me/wgrasel

define:

reactive programming 

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

O que mais pode ser um Stream?

  • Ações do usuário
  • Eventos do sistema
  • Estado da aplicação
  • Validações e regras de negócio
  • Qualquer fonte de dados, assíncrona ou não!

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]

Operadores ❤️


  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])
    )

Tá, e o que eu ganho com isso?

Show me the code!

Typeahead Search


  <input type="text" [(ngModel)]="myInput">
  <ul>
    <li *ngFor="let r of results">{{r.name}}</li>
  </ul>

  <input type="text" [formControl]="myInput">
  <ul>
    <li *ngFor="let r of results">{{r.name}}</li>
  </ul>

  <input type="text" [formControl]="myInput">
  <ul>
    <li *ngFor="let r of results | async">{{r.name}}</li>
  </ul>

  @Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
  })
  export class AppComponent {
    myInput = new FormControl;
    results = Observable.of([]);
  }

  @Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
  })
  export class AppComponent {
    myInput = new FormControl;
    results = Observable.of([])
      .merge(this.myInput.valueChanges);
  }

  @Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
  })
  export class AppComponent {
    myInput = new FormControl;
    results = Observable.of([])
      .merge(this.myInput.valueChanges)
      .map(v => `https://swapi.co/api/people/?search=${v}`);
  }

  @Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
  })
  export class AppComponent {
    myInput = new FormControl;
    results = Observable.of([])
      .merge(this.myInput.valueChanges)
      .map(v => `https://swapi.co/api/people/?search=${v}`)
      .mergeMap(url => this.http.get(url));

    constructor(private http: HttpClient) {}
  }

  @Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
  })
  export class AppComponent {
    myInput = new FormControl;
    results = Observable.of([])
      .merge(this.myInput.valueChanges)
      .map(v => `https://swapi.co/api/people/?search=${v}`)
      .switchMap(url => this.http.get(url))
      .map(json => json['results']);

    constructor(private http: HttpClient) {}
  }

  @Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
  })
  export class AppComponent {
    myInput = new FormControl;
    results = Observable.of([])
      .merge(this.myInput.valueChanges)
      .filter(v => v.length > 2)
      .map(v => `https://swapi.co/api/people/?search=${v}`)
      .switchMap(url => this.http.get(url))
      .map(json => json['results']);

    constructor(private http: HttpClient) {}
  }

  @Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
  })
  export class AppComponent {
    myInput = new FormControl;
    results = Observable.of([])
      .merge(this.myInput.valueChanges)
      .filter(v => v.length > 2)
      .debounceTime(300)
      .map(v => `https://swapi.co/api/people/?search=${v}`)
      .switchMap(url => this.http.get(url))
      .map(json => json['results']);

    constructor(private http: HttpClient) {}
  }

  @Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
  })
  export class AppComponent {
    myInput = new FormControl;
    results = Observable.of([])
      .merge(this.myInput.valueChanges)
      .map(v => `https://swapi.co/api/people/?search=${v}`)
      .mergeMap(url => this.http.get(url))
      .map(json => json['results']);

    constructor(private http: HttpClient) {}
  }

  @Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
  })
  export class AppComponent {
    myInput = new FormControl;
    results = Observable.of([])
      .merge(this.myInput.valueChanges)
      .filter(v => v.length > 2)
      .debounceTime(300)
      .map(v => `https://swapi.co/api/people/?search=${v}`)
      .switchMap(url => this.http.get(url))
      .map(json => json['results'])
      .retry(3);

    constructor(private http: HttpClient) {}
  }

Referências

Perguntas?

Obrigado! =)

Programação Reativa para Web na Prática

By William Grasel

Programação Reativa para Web na Prática

Passado o hype de programação reativa de uns cinco anos atrás, foi tempo suficiente para esse conceito e suas ferramentas amadurecerem em meio a comunidade. Nessa apresentação veremos técnicas avançadas de programação assíncrona, muito além de callbacks, promises e async/await, para domar todo tipo de fluxo de dados com facilidade, utilizando um pattern muito antigo chamado Observable. Tudo isso em meio a exemplos práticos com novas ferramentas para seu dia a dia!

  • 414
Loading comments...

More from William Grasel