Состояние ngrx undefined

Я пытаюсь инкапсулировать состояние ngrx в общий класс сервиса, чтобы абстрагировать детали реализации от моих компонентов.

Пример класса сервиса, который зарегистрирован в моем приложении .module.ts providers

@Injectable()
export class PatientService {

  state: Observable<PatientState>;

  constructor(
    private store: Store<AppState>,
  ) {
    this.state = store.select<PatientState>('patients');
  }

}

Я проверил свои действия, редуктор и эффекты работают, как ожидалось, однако, когда я подписываюсь на состояние службы в компоненте, он возвращает undefined.

Пример подписки компонента с использованием общей службы:

@Component({
  ...
})
export class DashboardComponent implements OnInit {

  constructor(
    private patientService: PatientService,
  ) {}

  ngOnInit(): void {
    // dispatches action to load patient from API
    this.patientService.loadPatient();

    this.patientService.state.subscribe(patientState => {
        console.log('patientState', patientState);
        // Does not work. Logs undefined.
    });
  }

}

Если я подписываюсь непосредственно в хранилище, он работает как ожидалось.

Пример:

@Component({
  ...
})
export class DashboardComponent implements OnInit {

  constructor(
    private patientActions: PatientActions,
    private store: Store<AppState>,
  ) {}

  ngOnInit(): void {
    this.store.dispatch(this.patientActions.loadPatient());

    this.store.select<PatientState>('patients').subscribe(patientState => {
        console.log('patientState', patientState);
        // Works as expected.
    });
  }

}

Что я делаю неправильно?

Ответ 1

Я реализовал аналогичный вариант использования. Ваша попытка хороша, и у меня получилось так:

@Injectable()
export class PatientService {
  // Define Observable
  patientState$: Observable<PatientState>;
  constructor(private store: Store<AppState>) {
    // Get data from the store
    this.patientState$ = store.select<PatientState>('patients');
  }

  getState(): PatientState {
    // subscribe to it so i don't have to deal with observables in components
    let patientState: PatientState = null;
    this.patientState$.subscribe(ps => patientState = ps);
    return patientState;
  }
}

Теперь вы можете вызывать этот метод из любого компонента, который вам нужен:

@Component({
  ...
})
export class DashboardComponent implements OnInit {
  patientState = new PatientState;
  constructor(
    private patientService: PatientService,
  ) {}

  ngOnInit(): void {
    // Simply get the Object from the store without dealing with observables
    this.patientState = this.patientService.getState();
  }

}

Я использую $ в конце наблюдаемых, так что каждый раз, когда я касаюсь переменной, я знаю, является ли она наблюдаемой или нет, так что я не путаюсь.

Ответ 2

Я думаю, что вам не хватает этой ссылки,

this.state = store.select<PatientState>('patients');

должно быть

this.state = this.store.select<PatientState>('patients');

Ответ 3

Я решил это, следуя совету Мергасова и установив условие по умолчанию:

У меня была похожая проблема: когда компонент подписывается на состояние, он всегда получает state === undefined. Это было очень запутано для меня, но в конце концов я обнаружил, что соответствующий редуктор не реализован магический код: default: return state;

Вот как это выглядит в контексте более крупного reducer.ts:

  export function reducer(state: EntityState= initialEntityState, action:  actions.EntityAction) {
    switch (action.type) {
      case actions.CREATE_ENTITY_SUCCESS:
      case actions.UPDATE_ENTITY_SUCCESS: {
        const EntityDetails = action.payload;
        const entities = {
          ...state.entities,
          [Entitydetails.Id]: EntityDetails,
        };
        return {
          ...state,
          error: null,
          entities,
        };
      }
      default : {
        return state;
      }
    }
 }

Ранее мой код не имел условия по default и возвращал undefined из-за этого факта. добавление условия по default для редуктора решило проблему.