Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get current value of State object with @ngrx/store?

My service class, before calling a web service, needs to get a property called dataForUpdate from my state. Currently, I'm doing it like this:

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

}

I'm using angular2-store-example (https://github.com/ngrx/angular2-store-example/blob/master/src/app/users/models/users.ts) as a guide to follow.

I'm wondering if a better (cleaner) way exists?

Live example: https://plnkr.co/edit/WRPfMzPolQsYNGzBUS1g?p=preview

like image 590
Philippe sillon Avatar asked Feb 25 '16 17:02

Philippe sillon


People also ask

What is the way to the reading state when using an NGRX based application?

To read your application state in Redux, we need to use the select() method on @ngrx's Store class. This method creates and returns an Observable that is bound to a specific property in your application state.

Where is NGRX state stored?

Where Does NgRx Store Data? NgRx stores the application state in an RxJS observable inside an Angular service called Store. At the same time, this service implements the Observable interface. So, when you subscribe to the store, the service actually forwards the subscription to the underlying observable.

What is store state NGRX?

NgRx Store provides reactive state management for Angular apps inspired by Redux. Unify the events in your application and derive state using RxJS.


3 Answers

Original answer for @ngrx/store v1.x

@ngrx/store extends BehaviorSubject and it has a value property you can use.

this._store.value

that will be the current state of your app, and from there you can select properties, filter, map etc...

update:

Took me a while to figure what's what in your example (: To get current value of dataForUpdate, you can use:

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

Update for @ngrx/store v2.x

With the update to version 2, value was removed as described in docs:

The APIs for synchronously pulling the most recent state value out of Store have been removed. Instead, you can always rely on subscribe() running synchronously if you have to get the state value:

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

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

    return state;
}
like image 55
Sasxa Avatar answered Oct 10 '22 03:10

Sasxa


Following the answer from @Sasxa, the syntax changed on newer versions of @nrgx/store (v5 and v6). After the underlying RxJS library was updated to ^5.5.0, there is now a pipe method available on all the Observable instances, which allows for easier chaining and changes how a subscription is achieved.

So you can now do something like:

import { take } from 'rxjs/operators';

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

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

   return state;
}

Or, using strictly the pipe() operator:

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

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

   store.pipe(select('your-state'), take(1)).subscribe(
      s => state = s
   );

   return state;
}

And if you want to make your code a bit more readable you can also employ async/await mechanics like so:

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

function async getStateAsync(store: Store<State>): State {
   let state = await store
             .pipe(
                select('your-state'),
                take(1)
             )
             .toPromise<State>();

   return state;
}
like image 28
carsanlop Avatar answered Oct 10 '22 02:10

carsanlop


withLatestFrom() or combineLatest() methods in the subscription chain give you just what you need, and are aligned with the spirit of Observables+Ngrx.

In place of the GET STATE .mergeMap() in the code above, using withLatestFrom() would look something like this:

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

As an aside, the code in the original question appears to be managing asynchronous effects of redux actions, which is exactly what the ngrx/effects library is for. I suggest you check it out. After you get Effects wired up, the code for managing asynchronous redux actions is much cleaner. This article by Jim Lynch was also super helpful to me: The Basics of "ngrx/effects", @Effect, and Async Middleware for "ngrx/store" in Angular 2

like image 14
Matthew Marichiba Avatar answered Oct 10 '22 03:10

Matthew Marichiba