使用@ngrx/store给Angular Material表格加数据报id未定义错误如何解决
错误原因
- @ngrx/entity 主键配置缺失
NgRx的EntityAdapter默认以实体的id字段作为唯一主键,你定义的PeriodicElement接口仅包含name字段,未配置主键,即使传递了正确的新增数据也会触发字段读取错误。 - Action分发逻辑错误
你在add方法中分发Action时仅传递了type标识,没有携带要新增的元素数据,导致reducer中拿到的payload为undefined,调用addOne方法时读取undefined的id字段直接报错。同时你混用了老式Action类和新式createAction写法,reducer监听的是createAction生成的Action实例,直接分发普通type对象无法触发对应的状态更新逻辑。 - 表格数据源未与NgRx状态绑定
当前表格数据源直接读取接口返回结果,没有和Store中的状态同步,新增数据到Store后表格也不会自动更新。
修复步骤
1. 配置EntityAdapter主键规则
如果name字段是全局唯一的,直接指定name作为主键:
// reducer.ts export const tableAdapter: EntityAdapter<PeriodicElement> = createEntityAdapter<PeriodicElement>({ selectId: (element: PeriodicElement) => element.name });
如果业务需要独立id字段,先修改实体定义:
// 接口定义 export interface PeriodicElement { id: number; name: string; }
2. 简化Action写法,修正分发逻辑
删掉冗余的老式Action类定义,统一用createAction写法:
// action.ts export const Add = '[PeriodicElement] Add'; export const addTable = createAction(Add, props<{payload:PeriodicElement}>()); export const loadTableSuccess = createAction('[PeriodicElement] Load Success', props<{payload:PeriodicElement[]}>());
修改组件的add方法,正确携带payload分发Action:
// 组件ts文件 add(name: string) { // 如果用id作为主键,需要自己生成唯一id,比如Date.now() const newElement: PeriodicElement = { name: name }; this.store.dispatch(addTable({ payload: newElement })); }
3. 同步Store状态与表格数据源
修改reducer新增接口数据批量存入逻辑:
// reducer.ts const tableReducer = createReducer( initialeState, on(TableActions.addTable, (state, { payload}) => { return tableAdapter.addOne(payload, state); }), on(TableActions.loadTableSuccess, (state, { payload}) => { return tableAdapter.setAll(payload, state); }) );
修改组件的状态订阅与接口请求逻辑,保证所有数据走Store统一管理:
// 组件ts文件 ngOnInit(): void { // 订阅Store数据同步到表格 this.store.select(tableSelector.selectAll).subscribe((res) => { this.dataSource.data = res; }); this.get(); } get() { this.tableService .getTableDetails() .subscribe((data: PeriodicElement[]) => { // 接口返回数据先存入Store this.store.dispatch(loadTableSuccess({ payload: data })); }); }
内容的提问来源于stack exchange,提问作者heliot truste
相关产品推荐
相关产品推荐

