web-dev-qa-db-ja.com

ngrxの状態は未定義です

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.
    });
  }

}

私は何が間違っているのですか?

12
Brandon

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条件を追加すると、問題が解決しました。

1
George Stocker

同様のユースケースを実装しました。あなたの試みは良いです、そして私はそれをこのように機能させました:

@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();
  }

}

オブザーバブルの最後に$を使用しているので、変数に触れるたびに、それがオブザーバブルであるかどうかがわかります。これにより、混乱することはありません。

0
ochs.tobi

私はあなたがこの参照を逃していると思います、

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

する必要があります

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