Estoy intentando encapsular mi estado ngrx en una clase de servicio compartido para abstraer los detalles de implementación de mis componentes.
Clase de servicio de ejemplo que está registrada en mis providers app.module.ts
@Injectable() export class PatientService { state: Observable<PatientState>; constructor( private store: Store<AppState>, ) { this.state = store.select<PatientState>('patients'); } } He verificado que mis acciones, el reductor y los efectos funcionan como se esperaba, sin embargo, cuando me suscribo al estado del servicio en un componente, devuelve undefined .
Ejemplo de suscripción de componente utilizando el servicio compartido:
@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. }); } }Si me suscribo directamente a la tienda, funciona como se esperaba.
Ejemplo:
@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. }); } }¿Qué estoy haciendo mal?
Resolví esto siguiendo el consejo de Mergasov y establecí una condición de caso predeterminada:
Tuve un problema similar: cuando un componente se suscribe al estado, obtiene
state === undefinedsiempre. Fue muy confuso para mí, pero finalmente encontré que el reductor correspondiente no está implementado código mágico:default: return state;
Así es como se ve eso en el contexto de un reducer.ts más grande:
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; } } } Anteriormente, mi código no tenía una condición default y regresaba undefined debido a ese hecho. agregar la condición default al reductor resolvió el problema.
He implementado un caso de uso similar. Tu intento es bueno, y lo hice funcionar de esta manera:
@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; } }Ahora puede llamar a este método desde cualquier componente que desee así:
@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(); } } Uso el $ al final de los observables para saber cada vez que toco una variable si es un Observable o no, de esta manera no me confundo.
Creo que te falta esta referencia,
this.state = store.select<PatientState>('patients');debiera ser
this.state = this.store.select<PatientState>('patients');