3

I'm trying to print the current state in ngrx using a minimal example:

interface AppState {
  counter : number;
}

export function Reducer(state : AppState = { counter : 0 }, action : Action) {
  console.log(`counter: ${state.counter}`);
  return { counter: state.counter + 1 };
}

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'app';

  constructor(private store : Store<AppState>) {
    let observable : Observable<number>;

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

    store.select('counter').subscribe(x => console.log(x));

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

This, however, prints undefined in the console:

counter: 0
app.component.ts:10 counter: 1
app.component.ts:10 counter: 2
app.component.ts:29 undefined    <---- It prints undefined
app.component.ts:10 counter: 3
app.component.ts:10 counter: 4

I still can't create a minimal sample that manages to get the current state in ngrx.

Edit: I've already looked at How to get current value of State object with @ngrx/store? and Getting current state in ngrx, but the answers there don't work for me, because store.take() and store.value are missing. My ngrx version is "@ngrx/store": "^5.0.0",, while the questions there handle ngrx v1 and v2.

sashoalm
  • 75,001
  • 122
  • 434
  • 781
  • Possible duplicate of [How to get current value of State object with @ngrx/store?](https://stackoverflow.com/questions/35633684/how-to-get-current-value-of-state-object-with-ngrx-store) – bygrace Feb 13 '18 at 13:49
  • Is your question about how to get current state or how to create a minimal example about how to get minimal state? The referenced questions answers how to do the first. If you are trying to do the second then it would help if you setup a stackblitz or something similar with complete, running code. There seems to be some problem with your setup. – bygrace Feb 13 '18 at 14:02
  • @bygrace I want a minimal sample. The problem is actually the answers there mention functions that are missing. Maybe something changed in ngrx, but both `value` and `take` are missing. – sashoalm Feb 13 '18 at 14:04
  • The accepted answer explains that `value` was removed in v2.x. `take` is just an rxjs operator. – bygrace Feb 13 '18 at 14:11
  • @bygrace OK, so what do I use then? My question is about using it with my version of ngrx, not with ngrx 1.0. Also, `take` is not a member of `Store`, whether it's part of rxjs or not. – sashoalm Feb 13 '18 at 14:15
  • The accepted answer mentions that you can rely on subscribe on store running synchronously. So you subscribe to the store and do something with the first value that comes through. The `take` operator is introduced so that you just take the first value. The `Update for @ngrx/store v2.x` part of the answer should work for you. What version of rxjs are you using? Are you using pipeable operators or still the ones on the prototype? – bygrace Feb 13 '18 at 14:18
  • @bygrace So is there a one-liner that I can use to replace `store.select('counter').subscribe(x => console.log(x));` that will work? How hard can it be to print out a number from the state. The second part of the answer doesn't actually say how to do it, it uses `store.take(1).subscribe(s => state = s);` and `take()` is not a member of `Store` in my case. – sashoalm Feb 13 '18 at 14:23
  • The two differences between what you are doing and the example is (1) that you are getting a slice of state and they are getting all of state and (2) they are using the rxjs (not ngrx) `take` operator to complete the subscription after the first value. If your selector isn't working right now then it isn't going to work by adding take. You have something wrong with your setup. If you don't see take on store then maybe you have to do `pipe(take(1))`. That is why I was asking about your version of rxjs. You can always put the take after your select too. – bygrace Feb 13 '18 at 14:33
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/165062/discussion-between-sashoalm-and-bygrace). – sashoalm Feb 13 '18 at 14:40

2 Answers2

3

Try to write a selector for your store:

export const getState = createFeatureSelector<YourStateInterface>('nameOfYourStore');

Using this selector within your component, will give you a Observable which you can then subscribe on.

@Component({
 selector: 'app-root',
 templateUrl: './app.component.html',
 styleUrls: ['./app.component.css']
})
export class AppComponent {
 title = 'app';

 myState: Observable<AppState>

 constructor(private store : Store<AppState>) {
  this.myState = this.store.select(fromRoot.getState);
 }
}

Within your template you can use the Observable like this:

<div>{{ myState|async|json }}</div>

..or you simply subscribe it within your component just like you did it before, but be careful and unsubscribe from the subscription inside the ngOnDestroy method in order to prevent a memory leak.

More information about selectors: https://toddmotto.com/ngrx-store-understanding-state-selectors

kauppfbi
  • 805
  • 1
  • 8
  • 24
-1

Make sure you import the StoreModule as followed in you app.module.ts:
imports: [ BrowserModule, FormsModule, StoreModule.forRoot({ counter: Reducer }) ],

I tried to recreate your example on stackblitz: https://stackblitz.com/edit/angular-bjun7b