Angular 7 NGRX 商店有未定义的状态

Angular 7 NGRX Store have undefined state

我的代码在 Angular7 中,使用 @ngrx/store7,有时我会得到未定义的状态(仅针对特定状态)

永远是"history"状态。

我的应用状态:

export interface IAppState {
  router?: RouterReducerState,
  delivery: IDeliveryState,
  events: IEventsState,
  families: IFamiliesState,
  googleDrive: IGoogleDriveState,
  spinner: ISpinnerState,
  user: IUserState,
  volunteerConstraints: IVolunteerConstraintsState,
  volunteers: IVolunteersState,
  history: IHistoryState
}

export const initialAppState: IAppState = {
  delivery: initialDeliveryState,
  events: initialEventsState,
  families: initialFamiliesState,
  googleDrive: initialGoogleDriveState,
  spinner: initialSpinnerState,
  user: initialUserState,
  volunteerConstraints: initialVolunteerConstraintsState,
  volunteers: initialVolunteersState,
  history: initialHistoryState
};

export function getInitialState(): IAppState {
  return initialAppState;
}

我的历史状态:

export interface IHistoryState {
  familyHistory: Array<FamilyHistoryModel>;
  familyHistoryPending: boolean;

  routeHistory: Array<RouteHistoryModel>;
  routeHistoryPending: boolean;

  deliveryHistory: Array<DeliveryHistoryChartModel>;

  volunteerRating: Array<VolunteerRatingModel>;
  volunteerRatingPending: number;

  initiated: boolean;
}

export const initialHistoryState: IHistoryState = {
  familyHistory: new Array<FamilyHistoryModel>(),
  familyHistoryPending: false,

  routeHistory: new Array<RouteHistoryModel>(),
  routeHistoryPending: false,

  deliveryHistory: new Array<DeliveryHistoryChartModel>(),

  volunteerRating: new Array<VolunteerRatingModel>(),
  volunteerRatingPending: 0,

  initiated: true
};

我的历史选择器:

const selectHistoryState = (state: IAppState) => state.history;

export const selectFamilyHistory = createSelector(
  selectHistoryState,
  (state: IHistoryState) => state.familyHistory
);

export const selectFamilyHistoryPending = createSelector(
  selectHistoryState,
  (state: IHistoryState) => state.familyHistoryPending
);

export const selectRouteHistory = createSelector(
  selectHistoryState,
  (state: IHistoryState) => state.routeHistory
);

export const selectRouteHistoryPending = createSelector(
  selectHistoryState,
  (state: IHistoryState) => state.routeHistoryPending
);

export const selectDeliveryHistory = createSelector(
  selectHistoryState,
  (state: IHistoryState) => state.deliveryHistory
);

export const selectVolunteerRating = createSelector(
  selectHistoryState,
  (state: IHistoryState) => state.volunteerRating
);
export const selectVolunteerRatingPending = createSelector(
  selectHistoryState,
  (state: IHistoryState) => state.volunteerRatingPending
);

我的应用减速器:

export const appReducers: ActionReducerMap<IAppState, any> = {
  router: routerReducer,
  delivery: deliveryReducer,
  events: eventsReducer,
  families: familiesReducer,
  googleDrive: googleDriveReducer,
  spinner: spinnerReducer,
  user: userReducer,
  volunteerConstraints: volunteerConstraintsReducer,
  volunteers: volunteersReducer,
  history: historyReducer
}

我的历史减速器:

export function historyReducer(
  state = initialHistoryState,
  action: actions.HistoryActions): IHistoryState {
  switch (action.type) {
    case actions.HistoryActionTypes.Initiate:
      return {
        ...state,
        initiated: true
      };

    case actions.HistoryActionTypes.GetFamilyHistory:
      return { 
        ...state,
        familyHistory: initialHistoryState.familyHistory,
        familyHistoryPending:true
      };

    case actions.HistoryActionTypes.GetFamilyHistorySuccess:
      return {
        ...state,
        familyHistory: action.payload,
        familyHistoryPending: false
      };

    case actions.HistoryActionTypes.GetFamilyHistoryFailure:
      return {
        ...state,
        familyHistoryPending: false
      };

    case actions.HistoryActionTypes.GetRouteHistory:
      return {
        ...state,
        routeHistory: initialHistoryState.routeHistory,
        routeHistoryPending: true
      };

    case actions.HistoryActionTypes.GetRouteHistorySuccess:
      return {
        ...state,
        routeHistory: action.payload,
        routeHistoryPending: false
      };

    case actions.HistoryActionTypes.GetRouteHistoryFailure:
      return {
        ...state,
        routeHistoryPending: false
      };

    case actions.HistoryActionTypes.GetDeliveryHistory:
      return {
        ...state,
        deliveryHistory: initialHistoryState.deliveryHistory
      };

    case actions.HistoryActionTypes.GetDeliveryHistorySuccess:
      return {
        ...state,
        deliveryHistory: action.payload
      };

     case actions.HistoryActionTypes.GetVolunteersRating:
      return {
        ...state,
        volunteerRating: initialHistoryState.volunteerRating,
        volunteerRatingPending: state.volunteerRatingPending + 1
      };

    case actions.HistoryActionTypes.GetVolunteersRatingSuccess:
      return {
        ...state,
        volunteerRating: action.payload,
        volunteerRatingPending: state.volunteerRatingPending - 1
      };

    case actions.HistoryActionTypes.GetVolunteersRatingFailure:
      return {
        ...state,
        volunteerRatingPending: state.volunteerRatingPending - 1 < 0 ? 0 : 
state.volunteerRatingPending - 1
      };
 }
}

一开始历史状态是未定义的(如图所示),只有在我发送一个历史动作并改变 reducer 中的状态后,它才会被启动。

我如何解决这个问题,让它像所有其他状态一样在开始时启动?

packge.json:

  "dependencies": {
    "@agm/core": "^1.0.0-beta.3",
    "@agm/js-marker-clusterer": "^1.0.0-beta.3",
    "@angular-mdl/core": "^6.0.1",
    "@angular-mdl/datepicker": "^6.0.0",
    "@angular-mdl/expansion-panel": "^6.0.0",
    "@angular-mdl/popover": "^6.0.0",
    "@angular-mdl/select": "^6.0.0",
    "@angular/animations": "~7.1.0",
    "@angular/cdk": "^7.2.2",
    "@angular/common": "~7.1.0",
    "@angular/compiler": "~7.1.0",
    "@angular/core": "~7.1.0",
    "@angular/forms": "~7.1.0",
    "@angular/http": "^7.2.2",
    "@angular/material": "^7.2.2",
    "@angular/platform-browser": "~7.1.0",
    "@angular/platform-browser-dynamic": "~7.1.0",
    "@angular/router": "~7.1.0",
    "@ngrx/effects": "^7.1.0",
    "@ngrx/router-store": "^7.1.0",
    "@ngrx/schematics": "^7.1.0",
    "@ngrx/store": "^7.1.0",
    "@ngrx/store-devtools": "^7.1.0",
    "@ngx-translate/core": "^10.0.2",
    "@ngx-translate/http-loader": "^3.0.1",
    "@swimlane/ngx-charts": "^10.0.0",
    "angular-2-local-storage": "^2.0.0",
    "angular2-moment": "^1.9.0",
    "angular2localization": "^1.4.2",
    "aos": "^2.3.4",
    "core-js": "^2.5.4",
    "crypto-js": "^3.1.9-1",
    "hammer-timejs": "^1.1.0",
    "hammerjs": "^2.0.8",
    "js-marker-clusterer": "^1.0.0",
    "jssha": "^2.3.1",
    "lodash": "^4.17.4",
    "lodash-es": "^4.17.4",
    "moment": "^2.20.1",
    "ngrx-store-freeze": "^0.1.9",
    "ngrx-store-localstorage": "^0.1.8",
    "ngrx-store-logger": "^0.1.8",
    "ngx-chips": "^1.4.5",
    "ngx-device-detector": "^1.3.0",
    "ngx-gallery": "^5.6.2",
    "ngx-infinite-scroll": "^0.5.1",
    "rxjs": "~6.3.3",
    "rxjs-compat": "^6.0.0",
    "sha.js": "^2.4.11",
    "tslib": "^1.9.0",
    "videogular2": "^6.3.0",
    "zone.js": "~0.8.26"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "~0.11.0",
    "@angular/cli": "~7.1.4",
    "@angular/compiler-cli": "~7.1.0",
    "@angular/language-service": "~7.1.0",
    "@types/core-js": "^2.5.0",
    "@types/googlemaps": "^3.30.16",
    "@types/jasmine": "~2.8.8",
    "@types/jasminewd2": "~2.0.3",
    "@types/node": "~8.9.4",
    "codelyzer": "~4.5.0",
    "jasmine-core": "~2.99.1",
    "jasmine-spec-reporter": "~4.2.1",
    "karma": "~3.1.1",
    "karma-chrome-launcher": "~2.2.0",
    "karma-coverage-istanbul-reporter": "~2.0.1",
    "karma-jasmine": "~1.1.2",
    "karma-jasmine-html-reporter": "^0.2.2",
    "protractor": "~5.4.0",
    "ts-node": "~7.0.0",
    "tslint": "~5.11.0",
    "typescript": "~3.1.6"
  }

在我看来,您的 history reducer 中缺少 default case。

switch(...) {
  case: ...
  case: ...
  default: {   
    return state;
  }
}