Angular Ngrx 8选择器错误:无法读取未定义的属性“ map”

时间:2019-10-28 10:03:36

标签: angular ngrx ngrx-store ngrx-effects ngrx-entity

我正在为Ngrx 8选择器而苦苦挣扎。我已经设法查询数据并将其保存到存储中,但是每当尝试使用选择器时,都会出现此错误“无法读取未定义的属性'map'”。

效果文件(ects-users.effects.ts)

import { Injectable } from '@angular/core';
import { Actions, ofType, createEffect } from '@ngrx/effects';
import { of } from 'rxjs';
import { map, catchError, switchMap } from 'rxjs/operators';

import * as fromExternalUsersActions from './external-user/external-user.actions';
import { UsersService } from '../../shared/services/crud/users.service';
import { ExternalUser } from './external-user/external-user.model';




@Injectable()
export class EctsUsersEffects {

  loadExternalUsersDetails$ = createEffect(() =>
    this.actions$
      .pipe(
        ofType(fromExternalUsersActions.initialLoadExternalUsers),
        switchMap(() =>
          this.externalUsersService.getAll()
            .pipe(
              map((externalUsers: any) => {
                const list: ExternalUser[] = externalUsers.payload;
                return fromExternalUsersActions.loadExternalUsers({ externalUsers: list });
              }),
              catchError(error => of(fromExternalUsersActions.loadExternalUsersFailure({ error })))
            ))
      ));






  constructor(private actions$: Actions, private externalUsersService: UsersService) { }

}

操作文件(external-user.actions.ts)

import { createAction, props } from '@ngrx/store';
import { Update } from '@ngrx/entity';

import { ExternalUser } from './external-user.model';


export const initialLoadExternalUsers = createAction(
  '[ExternalUser/API] Initial Load ExternalUsers',
);

export const loadExternalUsersFailure = createAction(
  '[ExternalUser/API] Load ExternalUsers Failure',
  props<{ error: any }>()
);

export const loadExternalUsers = createAction(
  '[ExternalUser/API] Load ExternalUsers',
  props<{ externalUsers: ExternalUser[] }>()
);



export const addExternalUser = createAction(
  '[ExternalUser/API] Add ExternalUser',
  props<{ externalUser: ExternalUser }>()
);

export const upsertExternalUser = createAction(
  '[ExternalUser/API] Upsert ExternalUser',
  props<{ externalUser: ExternalUser }>()
);

export const addExternalUsers = createAction(
  '[ExternalUser/API] Add ExternalUsers',
  props<{ externalUsers: ExternalUser[] }>()
);

export const upsertExternalUsers = createAction(
  '[ExternalUser/API] Upsert ExternalUsers',
  props<{ externalUsers: ExternalUser[] }>()
);

export const updateExternalUser = createAction(
  '[ExternalUser/API] Update ExternalUser',
  props<{ externalUser: Update<ExternalUser> }>()
);

export const updateExternalUsers = createAction(
  '[ExternalUser/API] Update ExternalUsers',
  props<{ externalUsers: Update<ExternalUser>[] }>()
);

export const deleteExternalUser = createAction(
  '[ExternalUser/API] Delete ExternalUser',
  props<{ id: string }>()
);

export const deleteExternalUsers = createAction(
  '[ExternalUser/API] Delete ExternalUsers',
  props<{ ids: string[] }>()
);

export const clearExternalUsers = createAction(
  '[ExternalUser/API] Clear ExternalUsers'
);

外部用户还原器(external-user.reducer.ts)

import { Action, createReducer, on } from '@ngrx/store';
import { EntityState, EntityAdapter, createEntityAdapter } from '@ngrx/entity';
import { ExternalUser } from './external-user.model';
import * as ExternalUserActions from './external-user.actions';

export const externalUsersFeatureKey = 'externalUsers';

export interface State extends EntityState<ExternalUser> {
  loaded: boolean;
  loading: boolean;
  ids: string[];
}

export const adapter: EntityAdapter<ExternalUser> = createEntityAdapter<ExternalUser>();

export const initialState: State = adapter.getInitialState({
  loaded: false,
  loading: false,
  ids: [],
});

const externalUserReducer = createReducer(
  initialState,
  on(ExternalUserActions.addExternalUser,
    (state, action) => adapter.addOne(action.externalUser, state)
  ),
  on(ExternalUserActions.upsertExternalUser,
    (state, action) => adapter.upsertOne(action.externalUser, state)
  ),
  on(ExternalUserActions.addExternalUsers,
    (state, action) => adapter.addMany(action.externalUsers, state)
  ),
  on(ExternalUserActions.upsertExternalUsers,
    (state, action) => adapter.upsertMany(action.externalUsers, state)
  ),
  on(ExternalUserActions.updateExternalUser,
    (state, action) => adapter.updateOne(action.externalUser, state)
  ),
  on(ExternalUserActions.updateExternalUsers,
    (state, action) => adapter.updateMany(action.externalUsers, state)
  ),
  on(ExternalUserActions.deleteExternalUser,
    (state, action) => adapter.removeOne(action.id, state)
  ),
  on(ExternalUserActions.deleteExternalUsers,
    (state, action) => adapter.removeMany(action.ids, state)
  ),
  on(ExternalUserActions.loadExternalUsers,
    (state, action) => adapter.addAll(action.externalUsers,
      {...state,
          loaded: true
      })
  ),
  on(ExternalUserActions.clearExternalUsers,
    state => adapter.removeAll(state)
  ),
);

export function reducer(state: State | undefined, action: Action) {
  return externalUserReducer(state, action);
}

export const getLoaded = (state: State) => state.loaded;

export const getLoading = (state: State) => state.loading;

export const getIds = (state: State) => state.ids;

export const {
  selectIds,
  selectEntities,
  selectAll,
  selectTotal,
} = adapter.getSelectors();

选择器文件(external-users.selectors.ts)

import { createFeatureSelector, createSelector } from '@ngrx/store';
import { ectsUsersFeatureKey} from '../reducers';
import * as fromExternalUsers from './external-user.reducer';

export const selectExternalUsersState = createFeatureSelector<fromExternalUsers.State>(ectsUsersFeatureKey);

export const selectAllUsers = createSelector(
    selectExternalUsersState,
    fromExternalUsers.selectAll
);

export const selectExternalUsers = createSelector(
    selectAllUsers,
    externalUsers => {
        return externalUsers.filter(externalUser => !externalUser.user.isInternalUser);
    }
);

常规Reducer文件(index.ts)

import {
  ActionReducerMap,
  MetaReducer
} from '@ngrx/store';
import { environment } from '../../../../environments/environment';
import * as fromExternalUser from '../external-user/external-user.reducer';
import * as fromOffice from '../office/office.reducer';

export const ectsUsersFeatureKey = 'ectsUsers';


export interface State {

  [fromExternalUser.externalUsersFeatureKey]: fromExternalUser.State;
  [fromOffice.officesFeatureKey]: fromOffice.State;
}

export const reducers: ActionReducerMap<State> = {

  [fromExternalUser.externalUsersFeatureKey]: fromExternalUser.reducer,
  [fromOffice.officesFeatureKey]: fromOffice.reducer,
};


export const metaReducers: MetaReducer<State>[] = !environment.production ? [] : [];

我在控制台上看到的错误

core.js:4002 ERROR TypeError: Cannot read property 'map' of undefined
    at entity.js:29
    at store.js:581
    at memoized (store.js:523)
    at defaultStateFn (store.js:550)
    at store.js:584
    at memoized (store.js:523)
    at store.js:581
    at memoized (store.js:523)
    at defaultStateFn (store.js:550)
    at store.js:584

2 个答案:

答案 0 :(得分:0)

您在正确的轨道上,文件entity.js:29在此行应具有以下内容:

var selectAll = createSelector(selectIds, selectEntities, function (ids, entities) {
            return ids.map(function (id) { return entities[id]; });
        });

这会将商店中的当前实体映射为数组,因为这些实体是json对象

您的错误意味着您的状态应该始终为数组(空或带有ID)时,其变量ids未定义

由于未定义ID,因此ids.map调用会引发您所获取的异常。

要解决此问题,建议您安装Redux DevTools并在chrome上打开页面。这样一来,您可以查看自己的状态正在发生什么,以及哪些已调度的动作会将ids属性设置为undefined。

答案 1 :(得分:0)

我破解了!

我在external-users.selectors.ts文件上传递了错误的featureKey名称 我更改了这一行:

export const selectExternalUsersState = createFeatureSelector<fromExternalUsers.State>(ectsUsersFeatureKey);

export const selectExternalUsersState = createFeatureSelector<fromExternalUsers.State>(fromExternalUsers.externalUsersFeatureKey);

然后将reducer参考导入到ects-users.module上,如下所示:

StoreModule.forFeature(fromExternalUser.externalUsersFeatureKey, fromExternalUser.reducer),