Ngrx状態を共有サービスクラスにカプセル化して、コンポーネントから実装の詳細を抽象化しようとしています。
App.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.
});
}
}
私は何が間違っているのですか?
Mergasov のアドバイスに従ってこれを解決し、デフォルトのケース条件を設定しました。
同様の問題がありました。コンポーネントが状態にサブスクライブすると、常に
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
条件を追加すると、問題が解決しました。
同様のユースケースを実装しました。あなたの試みは良いです、そして私はそれをこのように機能させました:
@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();
}
}
オブザーバブルの最後に$
を使用しているので、変数に触れるたびに、それがオブザーバブルであるかどうかがわかります。これにより、混乱することはありません。
私はあなたがこの参照を逃していると思います、
this.state = store.select<PatientState>('patients');
する必要があります
this.state = this.store.select<PatientState>('patients');