2
votes

Réaffecter Observable utilisé via le canal Async

Disons que dans mon Component j'ai un champ Observable , qui est récupéré via un Service , qui utilise HttpClient code>

onButtonPressed() {
  this.items$ = this.findItems();
}

<app-items [items]="items$ | async"></app-items>

Ensuite, lorsqu'une action est effectuée dans MyComponent , je dois actualiser cela items $

list, donc j'appelle le Service
@Component(...)
export class MyComponent {
  items$: Observable<readonly Item[]>;

  ngOnInit() {
    this.items$ = this.findItems();
  }

  private findItems() {
    return this.service
      .getItems(...)
      .pipe(
        // Other code omitted
        toArray<Item>()
      );
  }
}

Les questions sont, est-ce que le Async pipe s'abonner automatiquement au nouveau Observable ?
Dois-je demander un detectChanges () , étant donné que je suis sur la stratégie OnPush ?
Et surtout, est-ce la bonne approche?


2 commentaires

Pas besoin d'utiliser detectChanges . le tube asynchrone détectera les modifications et mettra à jour les valeurs.


@SachilaRanawaka cette question se pose parce que les nouveaux éléments ne semblent pas être rendus en utilisant la réaffectation, plus le tube async . Je vais lui donner une autre chance en essayant de chercher des erreurs


4 Réponses :


-2
votes

Le tube Async s'abonne-t-il automatiquement au nouvel Observable?

Le tube asynchrone s'abonne à un Observable ou Promise et renvoie la dernière valeur qu'il a émise. Lorsque le composant est détruit, le tube asynchrone se désabonne automatiquement pour éviter d'éventuelles fuites de mémoire.

Dois-je demander un detectChanges (), étant donné que je suis sur l'OnPush stratégie?

Vous n'en avez pas besoin. Lorsqu'une nouvelle valeur est émise, le tube asynchrone marque le composant à vérifier pour les modifications.

Est-ce la bonne approche? Je n'y vois aucun mal car l'abonnement sera automatiquement désabonné lorsque le composant sera détruit.


2 commentaires

Salut! Désolé, mais cela ne répond pas à la question sur la réaffectation du champ.


La question ne concerne pas le nouvel élément émis dans le flux canalisé actuel ... mais le comportement du tube asynchrone si l'observable est réaffecté avec un nouveau flux.



1
votes

Pour répondre à ma propre question, oui, un appel à ChangeDetectorRef # detectChanges est nécessaire si vous utilisez la stratégie de détection des changements OnPush .

private readonly items = new BehaviorSubject<readonly Item[]>([]);

constructor(...) {
  items$ = this.items.asObservable(); 
}

...

this.findItems().subscribe(items => this.items.next(items));

Il ne semble pas y avoir de manière "plus agréable" de faire cela, si ce n'est en utilisant un second [Behavior Subject.


Edit: I remarqué que la réaffectation et l'appel de detectChanges peuvent provoquer un scintillement.
En fin de compte, j'ai opté pour l'alternative BehaviorSubject .

constructor(
  ...
  private readonly changeDetectorRef: ChangeDetectorRef
) {}

onButtonPressed() {
  this.items$ = this.findItems();
  this.changeDetectorRef.detectChanges();
}

Ainsi, plus de réaffectation.


1 commentaires

Je pense que je trouve un moyen d'y parvenir sans utiliser d'abonnement, ni detectChanges () . Veuillez jeter un oeil à ma réponse.



1
votes

Vous pouvez utiliser le canal switchMap :

<app-items [items]="items$ | async"></app-items>

et continuer à utiliser:

@Component(...)
export class MyComponent {
  items$: Observable<readonly Item[]>;

  updater$: Subject<void> = new Subject<void>();

  ngOnInit() {
    this.items$ = this.updater$
      .pipe(
        switchMap<void, Observable<Items[]>>(() => this.findItems())
      )
  }

  onButtonPressed(){
    this.updater$.next();
  }

  private findItems() {
    return this.service
      .getItems(...)
      .pipe(
        // Other code omitted
        toArray<Item>()
      );
  }
}

switchMap ()

vous permet d'avoir une seule observable "jamais-réaffectée" ( updater $ ) et pour chaque émission sur ce flux, il "change" la valeur émise de l'observable pour envoyer le résultat de la fonction interne à la place, qui devrait être une observable.

Ici, chaque fois que vous appelez updater $ .next () , il "bascule" le void émis au résultat de la méthode findItems () , qui est votre tableau d'éléments.

La différence entre switchMap code > et mergeMap c'est que switchMap s'occupe de compléter et de fermer l'observable précédemment émis. Si vous appelez updater $ .next () deux fois, le deuxième appel de switchMap terminera la première observable renvoyée par le premier appel de findItems () code > et remplacez-le par un nouvel appel de cette méthode.

Sources:
https://www.learnrxjs.io/operators/transformation/switchmap.html
https://blog.angular-university.io/rxjs-higher-order -mappage /


0 commentaires

0
votes

Ce n'est pas une réponse sûre à 100% car elle n'est pas documentée, mais nous pouvons obtenir des indices en manipulant Promise par le tube async dans docs .

greeting: Promise<string>|null = null;
  private resolve: Function|null = null;

  constructor() {
    this.reset();
  }

  reset() {
    this.greeting = new Promise<string>((resolve, reject) => {
      this.resolve = resolve;
    });
  }

Ici, nous pouvons voir que la réaffectation de Promise doit déclencher une détection de changement sinon le code être inutile.


0 commentaires