Когда выполняются селекторы? ngxs

живая демонстрация https://stackblitz.com/edit/angular-vw78jf

В моем состоянии ngxs есть ToppingsStateModel

export interface ToppingsStateModel {
  entities: { [ id: number ]: Topping };
  selectedToppings: number[];
}

Одно действие изменяет список моих сущностей, другое действие изменяет selectedToppings. В products.component я получаю список начинок из селектора

export class ToppingsState {
  constructor(private toppingsService: ToppingsService) {
  }

  @Selector()
  static entities(state: ToppingsStateModel) {
    console.log('getEntities', state.entities);
    return state.entities;
  }

  @Selector([ToppingsState.entities])
  static toppings(state: ToppingsStateModel, entities: {[id: number]: Topping}): Topping[] {
    return Object.keys(entities).map(id => entities[parseInt(id, 10)]);
  }
 ...
}

и это product.component

export class ProductsComponent implements OnInit {

  @Select(ToppingsState.toppings) toppings$: Observable<Topping[]>;

  constructor(private store: Store, private actions$: Actions) {}

  ngOnInit() {
    const state = this.store.dispatch(new LoadToppings());
    setTimeout(() => this.store.dispatch(new VisualizeToppings([1])), 2000);
    this.toppings$.subscribe((toppings) => {console.log('UUUU NEW TOPPINGS!!!')});
  }
}

когда я отправляю действие VisualizeToppings, я получаю новое значение начинки. В моей консоли у меня есть

action [Products] Load Toppings @ 10:57:59.735
getEntities {}
UUUU NEW TOPPINGS!!!
getEntities {1: {…}, 2: {…}}
UUUU NEW TOPPINGS!!!
action [Products] Visualize Toppings @ 10:58:01.744
getEntities {1: {…}, 2: {…}}
UUUU NEW TOPPINGS!!!

Я изменил другую часть состояния. Почему селекторы сработали снова, когда я отправил действие VisualizeToppings? Что я делаю не так?


person Сергей    schedule 22.02.2019    source источник
comment
По памяти я думаю, что пользовательские селекторы выполняются каждый раз, когда происходит изменение состояния - не могу найти этого в документации, но, возможно, я читал это на NGXS github или в канале Slack. Я не думаю, что вы сделали что-то «неправильное», чтобы это произошло.   -  person Garth Mason    schedule 22.02.2019
comment
Что произойдет, если вы подпишетесь напрямую, если это не статический селектор, а ради интереса? например @Select (state = ›state.toppings.entities) начинки $ ..   -  person Garth Mason    schedule 22.02.2019
comment
Прямая подписка работает О_о Но это плохой способ решить проблему, мое мнение. P.S. в NGRX все работает правильно, когда я использую createSelector   -  person Сергей    schedule 22.02.2019


Ответы (1)


Существует известная проблема с @Selector, когда модель класса состояния контейнера всегда принимается в качестве первого параметра. См. https://github.com/ngxs/store/issues/386#issuecomment-395780734

Это ваша проблема ... Из-за этого первого параметра ваш селектор зависит от модели состояния ToppingsStateModel и указанного селектора ToppingsState.entities.

  @Selector([ToppingsState.entities])
  static toppings(state: ToppingsStateModel, entities: {[id: number]: Topping}): Topping[] {
    return Object.keys(entities).map(id => entities[parseInt(id, 10)]);
  }

Это приводит к пересчету селектора при изменении любой части ToppingsStateModel. В качестве обходного пути вы можете переместить селектор в другой класс, который не является классом состояния, и удалить первый параметр. Я называю их классами запросов. Это известно как мета-селектор, см. Документацию здесь: https://ngxs.gitbook.io/ngxs/concepts/select#meta-selectors

Это будет исправлено в рамках критических изменений в NGXS v4 (см. https://github.com/ngxs/store/issues/827), и в настоящее время существует PR для флага функции, чтобы изменить это поведение до появления NGXS v4. См .: https://github.com/ngxs/store/pull/858.

Надеюсь, это поможет и объяснит проблему.

person Mark Whitfeld    schedule 22.02.2019
comment
Спасибо за официальный ответ @Mark Whitield - person Garth Mason; 25.02.2019
comment
Спасибо, вы помогли понять - person Сергей; 25.02.2019