使用featureSelector ngrx时无法读取未定义地图的属性

Mat*_*ood 5 ngrx angular

回购协议:https : //github.com/morningharwood/platform/tree/feature/ngrx-firebase

当我尝试订阅我的post ngrx实体功能的selectAll时,收到错误消息:

无法读取未定义地图的属性

我必须逐字阅读教程,这必须是一个简单的错字。

奇怪的是,如果我使用字符串选择器:

 this.selected$ = this.store.select('post');

 this.selected$.subscribe(console.log); // no error here.
Run Code Online (Sandbox Code Playgroud)

我没有错误。

问题:使用ngrx实体时,如何获取selectAll选择器以注销ngrx商店集合中的所有帖子post?

我的 post.reducer.ts

import {
  PostActions,
  PostActionTypes,
} from './post.actions';

import {
  ActionReducerMap,
  createFeatureSelector,
} from '@ngrx/store';
import {
  createEntityAdapter,
  EntityState,
} from '@ngrx/entity';
import { Post } from './post.interfaces';

export const postAdapter = createEntityAdapter<Post>();
export interface PostState extends EntityState<Post> {}

export const postInitialState: PostState = {
  ids: [ '1234' ],
  entities: {
    '1234': {
      id: '1234',
      header: {
        title: 'title 1',
        subtitle: 'subtitle 1',
      },
      body: {
        sections: [],
      },
    },
  },
};

export const initialState: PostState = postAdapter.getInitialState(postInitialState);

export function postReducer(state: PostState = initialState, action: PostActions): PostState {
  switch (action.type) {
    case PostActionTypes.ADD_ONE:
      return postAdapter.addOne(action.post, state);
    default:
      return state;
  }
}

export const getPostState = createFeatureSelector<PostState>('post');
export const {
  selectIds,
  selectEntities,
  selectAll: selectAllPosts,
  selectTotal,
} = postAdapter.getSelectors(getPostState);

export const postReducersMap: ActionReducerMap<any> = {
  post: postReducer,
};
Run Code Online (Sandbox Code Playgroud)

和app.component:

import {
  Component,
  OnInit,
} from '@angular/core';
import { AppState } from './app.interfaces';
import { Store } from '@ngrx/store';
import { selectAllPosts } from './post/post.reducer';

import { Observable } from 'rxjs/Observable';


@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ],
})
export class AppComponent implements OnInit {
  public selected$: Observable<any>;

  constructor(private store: Store<AppState>) {
  }

  ngOnInit() {

    this.selected$ = this.store.select(selectAllPosts);
    this.selected$.subscribe(console.log); // error here
  }
}
Run Code Online (Sandbox Code Playgroud)

我forFeature和forRoot模块:

@NgModule({
  imports: [
    BrowserModule.withServerTransition({ appId: 'portfolio-app' }),
    StoreModule.forRoot({ reducers }),
    EffectsModule.forRoot([]),
    PostModule,
  ],
  declarations: [ AppComponent ],
  bootstrap: [ AppComponent ],
  providers: [],
})
export class AppModule {
}

import { StoreModule } from '@ngrx/store';
import { postReducers } from './post.reducer';


@NgModule({
  exports: [],
  declarations: [],
  imports: [StoreModule.forFeature('post', postReducersMap)],
})
export class PostModule {
}
Run Code Online (Sandbox Code Playgroud)

Jad*_*ams 6

对于将来遇到这种情况的人,可以通过稍微重构选择器来解决。

根据此处的文档(发布时有些不完整)ngrx.io/entity/adapter,您需要使用createFeatureSelector函数选择featureSate,然后将该子状态与适配器选择器一起使用以选择该状态的切片。

更改此:

post.reducer.ts

export const getPostState = createFeatureSelector<PostState>('post');
export const {
  selectIds,
  selectEntities,
  selectAll: selectAllPosts,
  selectTotal,
} = postAdapter.getSelectors(getPostState);
Run Code Online (Sandbox Code Playgroud)

对此:

export const selectPostState = createFeatureSelector<PostState>('post');
export const {
  selectIds,
  selectEntities,
  selectAll
  selectTotal,
} = postAdapter.getSelectors();

export const selectPostIds = createSelector(
  selectPostState,
  selectIds
 );

export const selectPostEntities = createSelector(
  selectPostState,
  selectEntities
);

export const selectAllPosts = createSelector(
  selectPostState,
  selectAll
);
Run Code Online (Sandbox Code Playgroud)

这将选择功能的子状态postState。

希望这可以帮助

编辑:因此,似乎上述两个示例是等效的,并且我所面临的问题与Matthew Harwood相同,并且使用不当ActionReducerMap。

我认为文档对此可能有些困惑,因为他们会认为和实体的状态与功能状态(例如延迟加载的状态)的状态相同。

虽然实体状态具有ID和实体等属性,但它们不需要像每个相似特征状态那样的化简,而仅需要一个化简器来覆盖该模型的所有实体状态。

例如

export const initialState: PostState = postAdapter.getInitialState(postInitialState);
Run Code Online (Sandbox Code Playgroud)

不需要一个化简器映射,PostAdapterState因为一个化简器

export function postReducer(state: PostState = initialState, action: 
PostActions): PostState {
  switch (action.type) {
    case PostActionTypes.ADD_ONE:
      return postAdapter.addOne(action.post, state);
    default:
      return state;
  }
}
Run Code Online (Sandbox Code Playgroud)

涵盖所有实体状态更新。

如果您在功能状态中有多个适配器状态(例如以下示例),则需要一个简化器映射。

假设您有一个“图书馆”功能状态,该状态以及书籍和杂志的实体。它看起来像下面的样子。

book.reducer.ts

export interface BookEntityState extends EntityState<Book> {
  selectedBookId: string | null;
}

const bookAdapter: EntityAdapter<Book> = createEntityAdapter<Book>();

export const initialBookState: BookEntityState = adapter.getInitialState({
  selectedBookId: null
});

export const bookReducer (...) ... etc
Run Code Online (Sandbox Code Playgroud)

magazine.reducer.ts

export interface MagazineEntityState extends EntityState<Magazine> {
  selectedMagazineId: string | null;
}

const magazineAdapter: EntityAdapter<Magazine> = createEntityAdapter<Magazine>();

export const initialMagazineState: MagazineEntityState = 
adapter.getInitialState({
  selectedMagazineId: null
});

export const magazineReducer (...) ... etc
Run Code Online (Sandbox Code Playgroud)

然后您的库功能状态可能类似于

library.reducer.ts

// Feature state,
export interface LibraryFeatureState {
  books: BookEntityState
  magazines: MagazineEntityState
}

// Reducer map of the lirbray
export const libraryReducersMap: ActionReducerMap<LibraryFeatureState> = {
  books: bookReducer,
  magazines: magazineReducer
};
Run Code Online (Sandbox Code Playgroud)

然后将功能状态添加到LibraryModule imports数组中的Store中。

library.module.ts

...
StoreModule.forFeature<LibraryFeatureState>('libraryState', 
libraryReducersMap),
...
Run Code Online (Sandbox Code Playgroud)

希望这对其他人有帮助。


Mat*_*ood 0

它的创建是ActionMapReducer在forFeature('post', postReducerMap); 我仍然需要弄清楚如何将实体和 ActionMapReducer 一起使用。