问题
I'm attempting to encapsulate my ngrx state in a shared service class to abstract the implementation details away from my components.
Example service class that is registered in my app.module.ts providers
@Injectable()
export class PatientService {
state: Observable<PatientState>;
constructor(
private store: Store<AppState>,
) {
this.state = store.select<PatientState>('patients');
}
}
I have verified my actions, reducer and effects are working as expected, however, when I subscribe to the service state in a component, it returns undefined
.
Example component subscription using the shared service:
@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.
});
}
}
If I subscribe directly to the store, it works as expected.
Example:
@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.
});
}
}
What am I doing wrong?
回答1:
I solved this by following Mergasov's advice and set a default case condtion:
I had the similar issue: when a component subscribes to state it gets
state === undefined
always. It was very confused for me, but finally I've found corresponding reducer is not implemented magic code:default: return state;
Here's how that looks in the context of a larger 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;
}
}
}
Previously, my code did not have a default
condition, and was returning undefined
due to that fact. adding the default
condition to the reducer resolved the issue.
回答2:
I have implemented a similar usecase. Your attempt is good, and I got it working this way:
@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;
}
}
Now you are able to call this method from any component you want like that:
@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();
}
}
I use the $
at the end of observables so I know every time I touch a variable if it is a Observable or not, this way I don't get confused.
回答3:
I think you're missing a this reference,
this.state = store.select<PatientState>('patients');
should be
this.state = this.store.select<PatientState>('patients');
来源:https://stackoverflow.com/questions/42742967/ngrx-state-is-undefined