NgRX实体:ID在州内未定义

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NgRX实体:ID在州内未定义相关的知识,希望对你有一定的参考价值。

我一直在虚拟的“Todo”项目中尝试@ ngrx / entity,只有一个AppModule,一个减速器和一个组件。但是,我在试用它时遇到了问题。

我的行为很简单,只是一些CRUD操作:

import { Action } from '@ngrx/store';
import { Todo }  from '../../models/todo';


export const CREATE = '[Todo] Create'
export const UPDATE = '[Todo] Update'
export const DELETE = '[Todo] Delete'

export class Create implements Action {
    readonly type = CREATE;
    constructor(public todo: Todo) { }
}

export class Update implements Action {
    readonly type = UPDATE;
    constructor(
        public id: string,
        public changes: Partial<Todo>,
      ) { }
}

export class Delete implements Action {
    readonly type = DELETE;
    constructor(public id: string) { }
}

export type TodoActions
= Create
| Update
| Delete;

然后我的reducer文件包含处理我的实体所需的一切:

import * as actions from './todo.actions';
import { EntityState, createEntityAdapter } from '@ngrx/entity';
import { createFeatureSelector } from '@ngrx/store';
import { Todo } from '../../models/todo';

export interface TodosState extends EntityState<Todo> {}
export const todoAdapter = createEntityAdapter<Todo>();

export const initialState: TodosState = todoAdapter.getInitialState();

export function todoReducer(state: TodosState = initialState, action: actions.TodoActions) {
    console.log("Got new action", action);
    switch(action.type) {
        case actions.CREATE:
            return todoAdapter.addOne(action.todo, state);
        case actions.UPDATE:
            return todoAdapter.updateOne({
                id: action.id,
                changes: action.changes
            }, state);
        case actions.DELETE:
            return todoAdapter.removeOne(action.id, state);
        default:
            return state;
    }
}

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

在我的app.module.ts文件中,我正在执行以下操作:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { StoreModule } from '@ngrx/store';
import { StoreDevtoolsModule } from '@ngrx/store-devtools';

import { AppComponent } from './app.component';
import { todoReducer } from './reducers/todo.reducer';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    StoreModule.forRoot({
      todo: todoReducer
    }),
    StoreDevtoolsModule.instrument({maxAge: 25}),
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

最后,在我的app.component.ts中,我只是想创建两个TODO:

import { Component, OnInit } from '@angular/core';
import { Store } from '@ngrx/store';
import { Observable } from 'rxjs/Observable';

import * as fromTodo from './reducers/todo.reducer';
import { Todo } from '../models/todo';
import { Create } from './reducers/todo.actions';


@Component({
    selector: 'app-root',
    template: `
    `,
    styles: []
})
export class AppComponent implements OnInit {

    public todos: Observable<Todo[]>;


    constructor(private store: Store<fromTodo.TodosState>) {
        this.store.dispatch(new Create({
            title: "Test todo",
            content: "This is a test todo",
            date: new Date()
        }))
        this.store.dispatch(new Create({
            title: "Test todo 2",
            content: "This is another todo",
            date: new Date()
        }))
    }

    ngOnInit() {
        this.todos = this.store.select(fromTodo.selectAll);
    }

}

然而,在运行之后,我检查了Redux DevTools。我看到它只创建了第一个TODO,它的id是“未定义的”。

App state after running the app and dispatching both events

我的减速机中的console.log显示@ngrx/store/init,以及[TODO]创建动作

此外,如果我通过我的组件中的ngFor | async尝试todos,我会根据我的尝试得到各种错误(主要是“无法读取'未定义的'map'属性)。

答案

经过一些研究,我注意到@ngrx/entity使用你使用的模型的id属性。在我的情况下,我的Todo模型没有任何id属性,所以@ngrx/entity无法处理我的实体。我认为它在内部生成了ids,但显然它没有。

因此,解决此问题的方法是将id属性添加到模型中,并在每次向项目添加项目时自动生成它。

例如,有一个Angular2 UUID模块。

在我的情况下,我使用ngrxAngularFire2,其中有createId()方法:const id = this.afs.createId()。然后我可以将它添加到我想要添加的项目,然后将其存储在我的Firestore数据库中。

以上是关于NgRX实体:ID在州内未定义的主要内容,如果未能解决你的问题,请参考以下文章

使用 NgRX 实体标准化 Api 响应

无法读取未定义(读取“地图”)NGRX 实体的属性

NGRX - 使用哈希而不是数组来表示状态

选择条件列但获取子查询返回超过 1 个值

使用 Angular ngrx 存储效果按 id 查询数据

范围内未定义简单的 AngularJS 表单