Comment obtenir la valeur actuelle de L'objet State avec @ngrx / store?

ma classe service, avant d'appeler un service web, doit obtenir une propriété appelée dataForUpdate à partir de mon état. Actuellement, je suis en train de faire comme ceci:

constructor ( public _store: Store<AppState>, 
              public _APIService:APIService) {

    const store$ =  this._store.select ('StateReducer');

    .../...

    let update = this.actions$.filter ( action => action.type==UPDATE )
                              .do( (action) => this._store.dispatch({type: REDUCER_UPDATING, payload : action.payload  }) )
      *** GET STATE ***==>    .mergeMap ( action => store$.map ( (state : AppState)=> state.dataForUpdate ).distinctUntilChanged(),
                                         (action, dataForUpdate) { 
                                                   return { type:action.type, payload : {employee:action.payload, dataForUpdate :dataForUpdate }    }; 
                                                            })
       * AND CALL API *==>    .mergeMap ( action =>this._APIService.updateEmployee(action.payload.employee, action.payload.dataForUpdate),
                                         (action, APIResult) => { return  { type:REDUCER_UPDATED }})
                              .share ();


    .../...

    let all = Observable.merge (update, ....);
    all.subscribe ((action:Action) => this._store.dispatch (action));

}

j'utilise angular2-store-example (https://github.com/ngrx/angular2-store-example/blob/master/src/app/users/models/users.ts) comme guide à suivre.

je me demande s'il existe un meilleur moyen (plus propre)?

exemple en direct: https://plnkr.co/edit/WRPfMzPolQsYNGzBUS1g?p=preview

29
demandé sur sashoalm 2016-02-25 20:03:15

8 réponses

réponse originale pour @ngrx / store v1.x

@ngrx/store s'étend BehaviorSubject et il a un value propriété que vous pouvez utiliser.

this._store.value

que sera l'état actuel de votre application, et à partir de là, vous pouvez sélectionner propriétés, filtre, carte etc...

mise à jour:

J'ai mis du temps à comprendre ce que contient votre exemple (: pour obtenir la valeur actuelle de dataForUpdate, vous pouvez utiliser:

let x = this._store.value.StateReducer.dataForUpdate;
console.log(x); // => { key: "123" }

mise à Jour pour @ngrx / store v2.x

Avec la mise à jour de la version 2, value a été supprimé, comme décrit dans docs:

les API pour extraire de façon synchrone la valeur de l'état le plus récent ont été retirées. Au lieu de cela, vous pouvez toujours compter sur subscribe() exécution synchrone si vous devez obtenir la valeur d'état:

function getState(store: Store<State>): State {
    let state: State;

    store.take(1).subscribe(s => state = s);

    return state;
}
45
répondu Sasxa 2016-06-13 15:45:35

withLatestFrom() ou

Au lieu de les OBTENIR de l'ÉTAT .mergeMap() dans le code ci-dessus, en utilisant withLatestFrom() ressemblerait à quelque chose comme ceci:

...
.withLatestFrom(store$, (payload, state) => { 
    return {payload: payload, stateData: state.data} 
} )
...

à part, le code dans la question originale semble gérer les effets asynchrones des actions de redux, ce qui est exactement ce que le ngrx / effets bibliothèque. Je vous suggère de vérifier hors. Une fois les effets branchés, le code de gestion des actions de redux asynchrones est beaucoup plus propre. Cet article de Jim Lynch a également été super utile pour moi: les Bases de La "ngrx/effets", @Effet, et Async Middleware pour "ngrx/store" dans Angulaire 2

7
répondu Matthew Marichiba 2018-07-20 08:37:30

Pas strictement une réponse directe à la question, mais j'ai trouvé cette page à la recherche pour savoir comment récupérer une valeur unique à partir de la boutique.

pour ce faire, vous pouvez injecter le State objet @ngrx/store comme indiqué ci-dessous:

import { State } from '@ngrx/store';

constructor (private state: State<AppState>) {
    let propertyValue = state.getValue().path.to.state.property;
}

state l'objet tient l'état courant dans un privé _value propriété, accessible par l' .getValue() méthode.

4
répondu Alex Currie-Clark 2017-12-03 12:36:56

j'ai créé une application minimaliste qui a un état avec 2 compteurs qui sont des propriétés de L'AppState, et 2 réducteurs. Chaque réducteur est lié à un compteur, et j'ai souscrit un observables pour chaque compteur qui va console.log sa valeur. Les réducteurs eux-mêmes écrivent aussi sur la console lorsqu'ils sont appelés.

il y a un bouton qui appelle les deux réducteurs en envoyant un événement. En outre, les 2 compteurs sont liés à 2 étiquettes, ainsi les changements dans eux montrent - <p>Counter: {{counter1 | async}}</p>.

Mapping chaque compteur à un réducteur est fait avec StoreModule.forRoot({ counter1: Reducer1, counter2 : Reducer2 })

import { Component, NgModule } from '@angular/core';
import { Store, Action, StoreModule } from '@ngrx/store';
import { Observable } from 'rxjs/Observable';
import { BrowserModule } from '@angular/platform-browser';

interface AppState {
  counter1 : number;
  counter2 : number;
}

export function Reducer1(counter : number = 0, action : Action) {
  console.log(`Called Reducer1: counter=${counter}`);
  return counter + 1;
}

export function Reducer2(counter : number = 0, action : Action) {
  console.log(`Called Reducer2: counter=${counter}`);
  return counter + 2;
}

@Component({
  selector: 'app-root',
  template: `<p>Counter: {{counter1 | async}}</p>
  <p>Counter: {{counter2 | async}}</p>
  <button (click)='increment()'>Increment</button>`
})
export class AppComponent {
  title = 'app';
  counter1 : Observable<number>;
  counter2 : Observable<number>;

  constructor(private store : Store<AppState>) {
    this.counter1 = this.store.select('counter1');
    this.counter2 = this.store.select('counter2');

    this.counter1.subscribe(x => console.log(`Subscribe event for counter1 fired: counter=${x}`));
    this.counter2.subscribe(x => console.log(`Subscribe event for counter2 fired: counter=${x}`));
  }

  increment() {
    this.store.dispatch({type:'foo'});
  }
}

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    StoreModule.forRoot({ counter1: Reducer1, counter2 : Reducer2 })
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
1
répondu sashoalm 2018-02-14 10:01:54

suite à la réponse de @Sasxa, la syntaxe a changé sur les nouvelles versions de @nrgx/store (v5 et v6). Après la mise à jour de la bibliothèque RxJS sous-jacente à ^5.5.0, il y a maintenant une méthode pipe disponible sur tous les Observable les instances, ce qui permet un enchaînement plus facile et modifie la façon dont un abonnement est obtenu.

alors vous pouvez maintenant faire quelque chose comme:

import { take } from 'rxjs/operators';

store.select('your-state').pipe(take(1)).subscribe(
    val => console.log(val)
);

Ou, en utilisant strictement les pipe() opérateur:

import { select } from '@ngrx/store';
import { take } from 'rxjs/operators';

store.pipe(select('your-state'), take(1)).subscribe(
    val => console.log(val)
);
1
répondu carsanlop 2018-09-29 17:30:36

Ma Solution


la classe D'État dans ngStore est un BehaviorSubject, donc nous pouvons l'injecter, et utiliser sa propriété value pour obtenir la dernière valeur.

constructor(private state:State<YourState>...) {

}

someMethod() {
    // WHAT'S MORE: you can use your selector directly on it!
    let v = yourSelector(this.state.value);
}
0
répondu Jason Song 2018-06-08 02:20:23

commentaire Supplémentaire. Quand je l'utilise._store.valeur.StateReducer.période actuelle.id

Transpiler retour "app/état/stateService.ts (133,35): erreur TS2339: la propriété "StateReducer" n'existe pas sur le type "AppState"."

constructor ( public _store: Store<AppState>) {

    const store$ =  this._store.select ('StateReducer');

    .../...


    let saveTransaction = this.actions$
                  .filter (action => action.type==SAVE_TRANSACTION )
                  .map (action => { return { type:SAVING_TRANSACTION, payload : action.payload };  } )
                  .mergeMap ( action => this._transactionService.updateTransaction (
                                                            this._store.value.StateReducer.currentProfile.id, 
                                                            this._store.value.StateReducer.currentPeriod.id, 
                                                            action.payload),
                                (state, webServiceResponse) =>  { return { type:TRANSACTION_UPDATED, payload :null  }; }) ;





}

pour corriger le problème, j'ai changé BehaviorSubject.d.ts en rxjs\dossier de sujet :

import { Subject } from '../Subject';
import { Subscriber } from '../Subscriber';
import { Subscription } from '../Subscription';
export declare class BehaviorSubject<T> extends Subject<T> {
    private _value;
    private _hasError;
    private _err;
    constructor(_value: T);
    getValue(): T;        
    value: T;             <=== I have changed it to value: any;
    _subscribe(subscriber: Subscriber<any>): Subscription<T>;
    _next(value: T): void;
    _error(err: any): void;
}

vous ne savez Pas si c'est une pièce de théâtre de la modification ;)

-1
répondu Philippe sillon 2016-02-25 18:58:25

c'est un travail pour moi. je vais obtenir mon objet de données.

this.store.select('dataStore').subscribe(data => { 
          console.log(data)
 }
-1
répondu sembilanlangit 2018-08-09 06:26:05