回购协议: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)
对于将来遇到这种情况的人,可以通过稍微重构选择器来解决。
根据此处的文档(发布时有些不完整)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)
希望这对其他人有帮助。
它的创建是ActionMapReducer在forFeature('post', postReducerMap); 我仍然需要弄清楚如何将实体和 ActionMapReducer 一起使用。
| 归档时间: |
|
| 查看次数: |
2912 次 |
| 最近记录: |