Состояние 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
для редуктора решило проблему.