ngxs / store

🚀 NGXS - State Management for Angular
http://ngxs.io
MIT License
3.54k stars 404 forks source link

Dynamic selector not triggered on setState #1543

Closed scaljeri closed 4 years ago

scaljeri commented 4 years ago

Description

I've done some testing with NGXS, to be more precise with Dynamic selectors. Unfortunate it is that part that I cannot get to work. I've tried to find answers on Stackoverflow without success. Anyway, I'm new to NGXS and this issue might be just stupidness or a document issue or even a bug. Let's find out

I have also created a stackblicz to reproduce the issue What happens in this stackblitz is that MainComponent updates the state, and NodeComponent should be notified of that change.

My State class looks like this:

...
export class MyState {
    @Selector([MyState])
    static foos(state: IMyState) {
        return state.foos;
    }

    @Selector([MyState.foos])
    static getFoo(fooId: string) {
        return createSelector([MyState], (state: IMyState) => {
            const outFoo = state.foos.filter(foo => foo.id === fooId)[0];
            return outFoo;
       });
    }

    @Action(MyStateActions.New)
     newState(ctx: StateContext<IMyState>, { payload }: { payload: IMyState }) {
         ctx.setState(payload);
    }
}

Then, in NodeComponent I listen for a specific state change

this.node$ = this.store.select(MyState.getFoo("xyz"));
this.node$.subscribe(foo => {
      console.log("NodeComponent@node$ -> new foo", foo);
      this.foo = foo;
 });

And finally, the new state is set in MainComponent as follows

 this.store.dispatch(new MyStateActions.New(NEW_STATE));

For some reason, the static methods in my state class are never called.

🔬 Minimal Reproduction

Checkout my stackblitz

Expected vs Actual Behavior**

What I expect is, that the below code receives an object and is printed to the console

this.node$ = this.store.select(MyState.getFoo("xyz"));
this.node$.subscribe(foo => {
  console.log("NodeComponent@node$ -> new foo", foo);
  this.foo = foo;
});

🌍 Your Environment

Angular 9.0.2 @ngxs/core 3.6.2

markwhitfeld commented 4 years ago

@scaljeri if you have a method that creates a selector using createSelector then you should not decorate that method with the @Selector decorator. This will be causing your issue

scaljeri commented 4 years ago

Ok, thanks, that explains it. I already noticed that the @selector was causing the issues :)

efelipe402 commented 3 years ago

@scaljeri @markwhitfeld Can you help with the same issue about selector but instead of using create selector I'm using @selector

My state

@Selector() static productPreviewFeatures(appConfig?: AppConfigState) { return appConfig.productPreview.requiredFields; }

something like this on the Angular Component variables @Select(AppConfigState.productPreviewFeatures) features$: Observable; and inside the ngOnit { this.features$.subscribe((features) => this.setFeatures(features)); } I'm subcribing to it, and when the components loads it retrieves the lastest value, but when I do a component action that change that selector value, it does not update my view any comments thanks a lot.

scaljeri commented 3 years ago

I think that we need more code, at least I do. Maybe you can fork my stackblitz and reproduce the issue?

markwhitfeld commented 3 years ago

@efelipe402 Is it possible that your selector may have an error? (set supressErrors to false in the selectorOptions in the options passed to your forRoot to check for this)

Or, that you are potentially mutating the objects in your state as opposed to doing immutable updates? (turn on the developmentMode in the forRoot options and check for errors related to mutations)

markwhitfeld commented 3 years ago

PS. @efelipe402 probably better to ask this in a separate issue (or on slack) because this is unrelated the original issue.