查询商店时出现 Angular NGRX 错误:类型错误:无法读取未定义的属性“地图”

问题描述

我已在我的 angular 应用程序中实现了 NGRX 效果,但出现以下错误。我不确定我是否在组件中正确使用选择器来查询商店?

core.js:6162 ERROR TypeError: Cannot read property 'map' of undefined
  at ngrx-entity.js:21
    at ngrx-store.js:1198
    at memoized (ngrx-store.js:1039)
    at defaultStateFn (ngrx-store.js:1079)
    at ngrx-store.js:1207
    at memoized (ngrx-store.js:1039)
    at ngrx-store.js:1078
    at Array.map (<anonymous>)

组件

ngOnInit() {
    this.initializeforModel();
    //this.users$ = this.store.select(getAllUsers);

    this.store.select(getAllUsers).pipe().subscribe((response:any)=> {
            this.listofUser = response.users;
            this.userMange = this._createGroup();
        
      });
      
  

选择器

export const userFeatureSelector = createFeatureSelector<UserState>('users');

        export const getAllUsers = createSelector(
          userFeatureSelector,selectAll,selectIds
        );

服务

  constructor(private http: HttpClient) { }
          getAllUsers(): Observable<any> {
          return this.http.get("assets/user.json");
          }
        }

减速器

  import { EntityState,EntityAdapter,createEntityAdapter } from '@ngrx/entity';
           
           export interface UserState extends EntityState<User> {
      usersLoaded: boolean;
    }

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

export const initialState  = adapter.getinitialState({
  usersLoaded: false,users: [
  
  ],});

export interface UserState {
  users: User[];
}
        
       export const userReducer = createReducer(
      initialState,on(UserActions.loadUsers,(state,{ users }) => {
        return adapter.setAll(users,state);
      }),

动作

export const loadUsers = createAction(
      '[Users List] Load Users via Service',props<{ users: User[] }>()
    );

效果

loadUsers$ = createEffect(() =>
    this.actions$.pipe(
      ofType(UserActions.loadUsers),mergeMap(() => this.UserService.getAllUsers()
     .pipe(
       map(users => ({ type: UserActions.loadUsers.type,payload: users }))
     // map(users =>  { {console.log(users)} return UserActions.usersLoaded({users})})()
    ))
    )
  );
        

解决方法

你不会错过选择器的返回值吗?而且, effect 应该返回一个你似乎不是的动作。你不也在那里得到一些错误吗?如果您不想要它,请将 URL 添加为 { dispatch: false} 函数的第二个参数。

createEffect()

编辑: 尝试从效果中分派一个动作或将其标记为不分派的效果

export const getAllUsers = createSelector(
  userFeatureSelector,selectAll,selectIds
  (feature,all,ids) => ({ feature,ids }) // In VS Code selector is underlined as faulty without this
);

我不经常使用 NgRx 实体/数据,所以我不确定它是如何工作的,但一般来说,reducer 在效果之前发生。因此,如果您希望在 loadUsers$ = createEffect(() => this.actions$.pipe( ofType(UserActions.loadUsers),mergeMap(() => this.UserService.getAllUsers() .pipe( map(users => ({ type: UserActions.loadUsers.type,payload: users })) )) ),//map(mappedUsers => this.store.dispatch(UserActions.saveUser({mappedUsers}))) // - Either dispatch an action to save mapped users { dispatch: false} // or add this param so that this effect does not need to dispatch new action ); 减速器中包含应该来自 BE 的数据,那么您就错了。它实际上应该是一个没有减速器的动作,如果 BE 调用成功,你可以分派具有减速器的新动作(如 `saveUsers),这个动作将保存你的数据。

编辑 2: 我想我明白你想要达到的目标。您希望修改 loadUsers 操作的有效负载有效,对吗?试试这个方法:

loadUsers

如果我理解正确,错误来自 NgRx 实体,它的发生是因为 // actions export const loadUsers = createAction('[Users List] Load Users via Service'); // empty export const saveUsers = createAction('[Users Effect] Save Users',props<{ users: User[] }>()); // reducer on(UserActions.saveUsers,(state,{ users }) => { return adapter.setAll(users,state); }),// effects loadUsers$ = createEffect(() => this.actions$.pipe( ofType(UserActions.loadUsers),concatMap(() => this.UserService.getAllUsers()),map(users => UserActions.saveUsers({ users })) )); 的减速器具有未定义的有效负载。您试图在效果中所做的实际上并不是更新有效负载,因为效果仅在减速器之后发生。

,

你需要像这样从 rxjs/operators 导入 Effects 中的贴图。

import { map,mergeMap,catchError } from "rxjs/operators";

,

我无法重现您遇到的确切错误,但能够让商店正常工作。

简单的商店结构如下

  1. 调度一个动作

在这里,我将您最初分派的操作更改为没有负载的操作

现在在我的动作文件中我创建了两个动作

import { createAction,props } from "@ngrx/store";
import { User } from "../reducers/user.reducer";

export const loadUsers = createAction(
  "[Users List] Load Users"
);

export const loadUsersSuccess = createAction(
  "[Users List] Load Users Success",props<{ users: User[] }>()
);

在组件中我们会有

this.store.dispatch(loadUsers());
  1. Effect 接收动作并发送另一个动作

在我们 dispatch 一个 action 后,effect 会收到这个 action。我们将需要调用该服务,一旦我们收到数据,就会发送一个带有有效载荷的新动作

@Injectable()
export class UserEffects {
  loadUsers$ = createEffect(() =>
    this.actions$.pipe(
      ofType(UserActions.loadUsers),mergeMap(() => this.UserService.getAllUsers()),map(users => UserActions.loadUsersSuccess({users}))
    )
  );

  constructor(private actions$: Actions,private UserService: MyService) {}
}

  1. Reducer 接收到 action 并将数据保存在 store 中

export const userReducer = createReducer(
  initialState,on(UserActions.loadUsers,state => {
    return adapter.setAll(state.users,state);
  }),on(UserActions.loadUsersSuccess,{ users }) => {
    return adapter.setAll(users,state);
  })
);

See this sample stackblitz demo