我正在与Ngrx 8选择器进行斗争。我已经设法查询数据并将其保存到存储中,但是每当我尝试使用选择器时,都会出现此错误“无法读取未定义的属性'map'”。
Effects File(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 Users Reducer(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);
}
);
General 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
您在正确的轨道上,文件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。