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(/* .. */);
