无法读取未定义(读取“地图”)NGRX 实体的属性
Posted
技术标签:
【中文标题】无法读取未定义(读取“地图”)NGRX 实体的属性【英文标题】:Cannot read properties of undefined (reading 'map') NGRX Entity 【发布时间】:2022-01-21 11:28:42 【问题描述】:它发生在 selectAll 选择器上,我查看了其他答案,我正在使用 createfeatureSelector 来调用状态。我已经设法调度动作,将状态保存到商店,但我不能使用选择器。任何帮助将不胜感激。
ERROR TypeError: Cannot read properties of undefined (reading 'map')
at ngrx-entity.mjs:21
at ngrx-store.mjs:697
at memoized (ngrx-store.mjs:578)
at defaultStateFn (ngrx-store.mjs:601)
at ngrx-store.mjs:700
at memoized (ngrx-store.mjs:578)
at ngrx-store.mjs:697
at memoized (ngrx-store.mjs:578)
at defaultStateFn (ngrx-store.mjs:601)
at ngrx-store.mjs:700
todos.actions.ts
import Update from "@ngrx/entity";
import createAction, props from "@ngrx/store";
import Todo from "../../../models/todo.interface";
export enum TodosActionTypes
GET_TODOS = '[todos] get todos',
GET_TODOS_FAIL = '[todos] get todos fail',
GET_TODOS_SUCCESS = '[todos] get todos success',
ADD_TODO = '[todo] add todo',
EDIT_TODO = '[todo] edit todo',
DELETE_TODO = '[todo] delete todo',
const getTodos = createAction(TodosActionTypes.GET_TODOS);
const getTodosFail = createAction(TodosActionTypes.GET_TODOS_FAIL, props<error: Error>());
const getTodosSuccess = createAction(TodosActionTypes.GET_TODOS_SUCCESS, props<todos: Todo[]>());
const editTodo = createAction(TodosActionTypes.EDIT_TODO, props<edit: Update<Todo>, completed: boolean>());
const deleteTodo = createAction(TodosActionTypes.DELETE_TODO, props<id: string>());
const addTodo = createAction(TodosActionTypes.ADD_TODO, props<todo: Todo>());
export const TodosActions =
getTodos,
getTodosFail,
getTodosSuccess,
editTodo,
deleteTodo,
addTodo
;
todos.reducer.ts
import createEntityAdapter, EntityAdapter, Update from '@ngrx/entity';
import createReducer, on from '@ngrx/store';
import Todo from '../../../models/todo.interface';
import TodosState from '../../../models/todos-state.interface';
import TodosActions from '../actions/todos.actions';
export function selectTodoId(a: Todo): string
return a.id;
export function sortByName(a: Todo, b: Todo): number
return a.name.localeCompare(b.name);
export const adapter: EntityAdapter<Todo> = createEntityAdapter<Todo>(
selectId: selectTodoId,
sortComparer: sortByName,
);
export const initalState: TodosState = adapter.getInitialState(
loading: false,
loaded: false,
error:
message: '',
name: '',
,
);
function getTodosHandler(state = initalState)
return
...state,
loading: true,
;
function getTodosFailHandler(state = initalState, action: error: Error )
return
...state,
loading: false,
loaded: true,
error: action.error,
;
function getTodosSuccessHandler(
state = initalState,
action: todos: Todo[]
)
return adapter.addMany(action.todos,
...state,
loading: false,
loaded: true,
);
function editTodosHandler(state = initalState, action: edit: Update<Todo> )
return adapter.updateOne(action.edit,
...state,
);
function deleteTodoHandler(state = initalState, action: id: string )
return adapter.removeOne(action.id,
...state,
);
function addTodoHandler(state = initalState, action: todo: Todo)
return adapter.addOne(action.todo,
...state,
)
export const TodosReducer = createReducer(
initalState,
on(TodosActions.getTodos, getTodosHandler),
on(TodosActions.getTodosFail, getTodosFailHandler),
on(TodosActions.getTodosSuccess, getTodosSuccessHandler),
on(TodosActions.editTodo, editTodosHandler),
on(TodosActions.deleteTodo, deleteTodoHandler),
on(TodosActions.addTodo, addTodoHandler)
);
todos.selectors.ts
import createFeatureSelector, createSelector from '@ngrx/store';
import TodosState from '../../../models/todos-state.interface';
import adapter from '../reducers/todos.reducers';
import Todo from '../../../models/todo.interface';
const selectIds, selectEntities, selectAll, selectTotal =
adapter.getSelectors();
export const getTodosFeatureState =
createFeatureSelector<TodosState>('todos');
const getTodosLoading = (state: TodosState): boolean => state.loading;
const getTodosLoaded = (state: TodosState): boolean => state.loaded;
const selectAllTodos = createSelector(getTodosFeatureState, selectAll);
const selectCompletedTodos = createSelector(selectAllTodos, (todos: Todo[]) => todos.filter(todo => todo.completed === true));
const selectTodosLoading = createSelector(getTodosFeatureState, getTodosLoading);
const selectTodosLoaded = createSelector(getTodosFeatureState, getTodosLoaded);
const selectAllTodosIds = createSelector(getTodosFeatureState, selectIds);
const selectAllTodosEntities = createSelector(getTodosFeatureState, selectEntities);
const selectTodosTotal = createSelector(getTodosFeatureState, selectTotal);
export const TodosSelectors =
selectAllTodos,
selectCompletedTodos,
selectTodosLoading,
selectTodosLoaded,
selectAllTodosIds,
selectAllTodosEntities,
selectTodosTotal
todos-index.reducer.ts
import ActionReducerMap from '@ngrx/store';
import TodosState from '../../../models/todos-state.interface';
import * as fromTodosReducer from './todos.reducers';
export interface TodosFeatureState
todos: TodosState;
export const reducers: ActionReducerMap<TodosFeatureState> =
todos: fromTodosReducer.TodosReducer,
;
todos.effect.ts
import Injectable from '@angular/core';
import Actions, createEffect, ofType from '@ngrx/effects';
import catchError, map, switchMap, take, from 'rxjs';
import Todo from '../../../models/todo.interface';
import TodosService from '../../../services/todos.service';
import TodosActions, TodosActionTypes from '../actions/todos.actions';
@Injectable()
export class TodosEffects
constructor(private todosService: TodosService, private actions$: Actions)
loadTodos$ = createEffect(() =>
this.actions$.pipe(
ofType(TodosActionTypes.GET_TODOS),
switchMap(() =>
this.todosService.getTodos().pipe(
take(1),
map((todos: Todo[]) => TodosActions.getTodosSuccess( todos )),
catchError(async (error: Error) =>
TodosActions.getTodosFail( error )
)
)
)
)
);
todosStateModule
import NgModule from "@angular/core";
import EffectsModule from "@ngrx/effects";
import StoreModule from "@ngrx/store";
import SnackBarService from "../../services/snackbar.service";
import TodosEffects from "./effects/todos.effects";
import * as fromTodos from './reducers/todos-index.reducers';
@NgModule(
imports: [
StoreModule.forFeature('todos', fromTodos.reducers),
EffectsModule.forFeature([TodosEffects]),
],
providers:[SnackBarService]
)
export class TodosNgrxStateModule
我的 package.json
"name": "marin-software",
"version": "0.0.0",
"license": "MIT",
"scripts":
"ng": "nx",
"postinstall": "node ./decorate-angular-cli.js && ngcc --properties es2015 browser module main",
"start": "nx serve",
"build": "nx build",
"test": "nx test"
,
"private": true,
"dependencies":
"@angular/animations": "~13.1.0",
"@angular/cdk": "^13.1.1",
"@angular/common": "~13.1.0",
"@angular/compiler": "~13.1.0",
"@angular/core": "~13.1.0",
"@angular/forms": "~13.1.0",
"@angular/material": "^13.1.1",
"@angular/platform-browser": "~13.1.0",
"@angular/platform-browser-dynamic": "~13.1.0",
"@angular/router": "~13.1.0",
"@ngrx/effects": "^13.0.2",
"@ngrx/entity": "^13.0.2",
"@ngrx/store": "^13.0.2",
"@ngrx/store-devtools": "^13.0.2",
"@nrwl/angular": "13.3.9",
"@tailwindcss/forms": "^0.4.0",
"@tailwindcss/typography": "^0.5.0",
"rxjs": "~7.4.0",
"tslib": "^2.0.0",
"zone.js": "~0.11.4"
,
"devDependencies":
"@angular-devkit/build-angular": "~13.1.0",
"@angular-eslint/eslint-plugin": "~13.0.1",
"@angular-eslint/eslint-plugin-template": "~13.0.1",
"@angular-eslint/template-parser": "~13.0.1",
"@angular/cli": "~13.1.0",
"@angular/compiler-cli": "~13.1.0",
"@angular/language-service": "~13.1.0",
"@nrwl/cli": "13.3.9",
"@nrwl/cypress": "13.3.9",
"@nrwl/eslint-plugin-nx": "13.3.9",
"@nrwl/jest": "13.3.9",
"@nrwl/linter": "13.3.9",
"@nrwl/nx-cloud": "latest",
"@nrwl/tao": "13.3.9",
"@nrwl/workspace": "13.3.9",
"@types/jest": "27.0.2",
"@types/node": "14.14.33",
"@typescript-eslint/eslint-plugin": "~5.3.0",
"@typescript-eslint/parser": "~5.3.0",
"cypress": "^9.1.0",
"eslint": "8.2.0",
"eslint-config-prettier": "8.1.0",
"eslint-plugin-cypress": "^2.10.3",
"jest": "27.2.3",
"jest-preset-angular": "11.0.0",
"prettier": "^2.3.1",
"tailwindcss": "^3.0.7",
"ts-jest": "27.0.5",
"typescript": "~4.4.3"
【问题讨论】:
【参考方案1】:试试这个
export const getFeatureState =
createFeatureSelector<TodosState>('todos');
export const getTodosFeatureState =
createSelector(getFeatureState,state => state.todos);
const selectAllTodos = createSelector(getTodosFeatureState, selectAll);
【讨论】:
这不适用于 NGRX 实体。这是 entityState 接口 ``` export interface TodosState extends EntityState以上是关于无法读取未定义(读取“地图”)NGRX 实体的属性的主要内容,如果未能解决你的问题,请参考以下文章
无法使用 Ngrx 读取未定义的属性“firebaseApp”
错误:无法在 reactjs 项目中读取未定义的属性(读取“地图”)\