Vyhledávání na webu

typescript - Angular ngrx/store - proč metoda subscribe na observable vrací předchozí stav?


Problém se zdá být nad mé schopnosti. Sklad jsem vytvořil správně a nyní nemohu získat aktuální prvek ze skladu.

showDialog(id_clicked) {
    this.id = id_clicked
    this.store.dispatch(new action.loadExampleAction(this.id));
    this.observable$ = this.store.select(selectors.getObject);
}

S tímto jednoduchým příkladem aktualizuji „observable“ vždy, když je kliknuto na tlačítko, a spouštím novou akci s aktuálně vybraným ID. Zobrazení this.observable$ v konzoli správně ukazuje aktuálně vybraný objekt ve svém payloadu. Ale nyní, když udělám toto:

tmp: <Object> = null
showDialog(id_clicked) {
        this.id = id_clicked
        this.store.dispatch(new action.loadExampleAction(this.id));
        this.observable$ = this.store.select(selectors.getObject);

        this.observable$.subscribe(object => {
        this.tmp = object
        }, first())
        console.log(this.tmp)
}

tmp uvnitř subscribe vrací předchozí stav. Tj. pokud nejdříve kliknu na objekt s id=1, vrátí se „undefined“, pak když kliknu na objekt s id=2, vrátí se objekt s id=1, a tak dále. I když console.log na this.observable$ukazuje, že jeho payload (hodnota) je správná. Nejsem si jistý, co se děje. Nemohu jednoduše získat aktuální hodnotu z tohoto observable. Pokud bude potřeba cokoli dalšího o tom, poskytnu další informace.

Odpověď č. 1

Měli byste se vyhýbat přerušování řetězce Observable, kde je to možné, a také se vyhýbat používání lokálních proměnných. Nepoužívejte svou proměnnou tmp a místo toho uchovejte observable$, a inicializujte ji v ngOnInit(). Pak, kdekoliv potřebujete spotřebovat observable$, přihlaste se k němu vhodným způsobem (obvykle pomocí pipe async):

ngOnInit() {
  this.observable$ = this.store.select(selectors.getObject);
}

showDialog(idClicked: string) {
  this.store.dispatch(new action.loadExampleAction(this.id));
}

Později, někde v šabloně:

<ng-container *ngIf="observable$ | async as myStuff">
</ng-container>

Odpověď č. 2

Nejsem si jistý, ale zdá se, že se snažíte získat pouze první hodnotu, která se objeví v odběru pomocí first().

Problém je, že NgRx používá memoizaci pro selektory a může vracet předchozí hodnotu, pokud se stav pro tento selektor ještě nezměnil. Takže když se přihlásíte k odběru, vrátí se počáteční hodnota undefined, po kliknutí nastavíte stav na "1", ale nedostali jste ji, protože jste vzali pouze první hodnotu v odběru.

Také klikání je asynchronní operace, takže když kliknete podruhé na další objekt, je vytvořeno nové předplatné a okamžitě se vrátí hodnota uložená ve skladu, je to 1, vidíte ji na obrazovce a teprve poté, kvůli asynchronní povaze „kliknutí“, se nová hodnota ve skladu stane „2“, ale neviděli jste ji, dokud nekliknete na další objekt a neuvidíte starou hodnotu.

Jako řešení můžete ve svém kódu odstranit možnost first(), ale pak dostanete dvě hodnoty, předchozí a následující, tedy aktuální. Aby se tomu předešlo, můžete vyzkoušet použití „Resetování memoizovaných selectorů“ pomocí funkce release(); z dokumentace a poté filtrovat hodnoty 'null' v pipe takto:

store
  .pipe(
    select(selectValues),
    filter(val => val !== null)
  )
  .subscribe(/* .. */);