Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Guideline for memoized selectors in state base class

Tags:

ngxs

I have a question regarding NGXS Store and the usage of memoized @Selector()s in a state class hierarchy.

What would be the recommended approach to the issue described below? The NGXS Store documentation does not provide a guideline/recommendation in this regard.

Given this sample state setup,


export interface BaseModel { data: string[]; }

// base class not a state!
export class BaseState {
  @Selector()
  static dataSelect(state: BaseModel) { return state.data; }

  // ...
}

export interface DerivedModel extends BaseModel {}

@State<DerivedModel>({ name: 'derived'; })
export class DerivedState extends BaseState {
  // ...
}   

export interface UsingModel { thing: number; }

@State<UsingModel>({ name: 'using'; })
export class UsingState implements NgxsOnInit {

  constructor(private _store: Store) {}

  ngxsOnInit(ctx: StateContext<UsingModel>) {
    // have this state update when derived state changes
    this._store.select(DerivedState.dataSelect).subscribe(data => console.log(data));
  }

  // ...
}

When letting this piece of code run it will print out undefined because the state argument of the dataSelect(...) method will not be set.

I tracked the cause to BaseState not being a NGXS State and therefore missing an internal NGXS_META property which in turn causes the undefined argument. Adding BaseState to the selector (such as @Selector([BaseState])) to force the state to still be included also does not have the desired effect, because now NGXS cannot navigate to a matching state slice.

I found two ways to make this work as desired: 1. duplicate the @Selector(...) method in every derived state implementation. This though defeats the reasons why the state class hierarchy was originally designed. 2. use something like @DerivedSelector(...) that works according to the standard decorator but dynamically creates selectors on use for each of the encountered derived state classes.

Thank you.

like image 782
mjtrjk Avatar asked Dec 10 '25 11:12

mjtrjk


1 Answers

As far as I know this can not be achived using the @Selector annotation, but with createSelector().

export class BaseState {
  static dataSelect() {
    return createSelector(
      [this],
      (state: BaseModel) => {
        return state.data;
      }
    );
  }

  //...
}

If you change your base state like this, your code will work. For details refer to the NGXS docs

like image 65
Grochni Avatar answered Dec 13 '25 22:12

Grochni



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!