ngrx 使用 memoization 方法选择特定对象 id 的数据
ngrx selecting data of specific object id with memoization method
我的问题是关于 ngrx4(使用 angular5)。
我正在开发具有以下数据结构的应用程序:
-> store
--> forums: id, name
--> posts: id, message, forumid
当我展示 post 时,我也会展示它的论坛。所以 post 表示将是:
postid, message, forum.id, forum.name
从 ngrx 示例应用程序我了解到获取论坛数据的方法是:
- 添加selectedForumId到论坛状态
- 获取 post 时:调度事件以将 selectedForumId 更新为 post 的论坛 ID
- select 论坛数据 selectedForumId
在代码中:
home.component.ts:
ngOnInit() {
this.store.dispatch(new postActions.GetAllPostsAction());
this.posts$ = store.select(fromReducers.getAllPosts);
}
home.component.html:
<post *ngFor="let post of (posts$|async)" [post]="post"></post>
post.component.ts:
@Input() post: Post;
ngOnInit() {
this.store.dispatch(new forumActions.SelectForumAction(this.post.forumId));
this.forum$ = this.store.select(fromReducers.getSelectedForum);
}
forum.reducer.ts:
export interface State extends EntityState<Forum> {
selectedForumId: number | null;
};
export function reducer(state = initialState, action: ForumActions): State {
switch (action.type) {
case ForumActionTypes.SELECT_FORUM:
return {
...state,
selectedForumId: action.payload,
};
...
export const getSelectedForumId = (state: State) => state.selectedForumId;
reducers/index.ts:
export const selectForumState = createFeatureSelector<fromForum.State>('forums');
export const selectForumEntities = createSelector(selectForumState, fromForum.selectForumEntities);
export const selectedForumId = createSelector(selectForumState, fromForum.getSelectedForumId);
export const getSelectedForum = createSelector<State, any, any, Forum>(selectForumEntities, selectedForumId,
(entities, id) => entities[id]
);
问题 -
我对这种方法的问题是,如果我在一个页面中有 10 个 post,这意味着我将发送更新 selectedForumId 10 次的操作,但感觉不对。
有没有我可以使用的更好的实践方法,它仍然会利用 createSelector 的优势来创建记忆 selector?
1) 在我的例子中,当我从我的商店中获取数据时,我做了一些错误的做法,里面应该是一个愚蠢的组件 (post.component.ts)
2) 第一个解决方案
起初我有这个问题:
@Ngrx/store: how to query models with relationships
评论中有对以下文章的 link:https://netbasal.com/querying-a-normalized-state-with-rxjs-in-angular-71ecd7ca25b4
这篇文章让我实现了解决方案:
posts.service.ts:
getPostsViewModel(posts$: Observable<Post[]>, users$: Observable<User[]>, forums$: Observable<Forum[]>): Observable<PostView[]> {
return Observable.combineLatest(posts$, users$, forums$, (posts, users, forums) => {
return posts.map(post => Object.assign({}, post, {
user: users.find(user => user.id === post.userId),
forum: forums.find(forum => forum.id === post.forumId)
}))
});
}
home.component.ts:
ngOnInit() {
this.store.dispatch(new postActions.GetAllPostsAction());
this.postsView$ = this.postService.getPostsViewModel(
this.store.select(fromReducers.getAllPosts),
this.store.select(fromReducers.getAllUsers),
this.store.select(fromReducers.getAllForums));
}
这个解决方案有效!
3) 第二种解法
但我仍然对我没有使用 createSelector 记忆功能感到困扰。有了这种新方法,我试图思考如何将其应用到 createSelector 中,答案如下:
reducers/index.ts:
export const selectPostIds = createSelector(selectPostState, fromPost.selectPostIds);
export const selectPostEntities = createSelector(selectPostState, fromPost.selectPostEntities);
export const selectedForumId = createSelector(selectForumState, fromForum.getSelectedForumId);
export const getAllUsers = createSelector<State, any, any, User[]>(selectUserEntities, selectUserIds,
(entities, ids) => ids.map(id => entities[id])
);
export const getAllForums = createSelector<State, any, any, Forum[]>(selectForumEntities, selectForumIds,
(entities, ids) => ids.map(id => entities[id])
);
export const getAllPosts = createSelector<State, any, any, any, any, PostView[]>(selectPostEntities, selectPostIds, getAllUsers, getAllForums,
(entities, ids, users, forums) => {
let posts = ids.map(id => entities[id]);
return posts.map(post => Object.assign({}, post, {
user: users.find(user => user.id === post.userId),
forum: forums.find(forum => forum.id === post.forumId)
}));
}
);
home.component.ts:
ngOnInit() {
this.store.dispatch(new postActions.GetAllPostsAction());
this.posts$ = this.store.select(fromReducers.getAllPosts);
}
现在我在 createSelector() 中有了解决方案!
我还是想知道 -
我的实现中的记忆过程是否足够好?
创建一个名为的方法不是更好吗:
getForumFromListOfForums(论坛:论坛[], forumId)
并使用 loadsh 来记忆它?
然后从 post.component.ts 转到它,让每个 post 请求它的论坛?
如果论坛在响应被记忆之前已经被问过,那么将是 O(1)。
我的问题是关于 ngrx4(使用 angular5)。
我正在开发具有以下数据结构的应用程序:
-> store
--> forums: id, name
--> posts: id, message, forumid
当我展示 post 时,我也会展示它的论坛。所以 post 表示将是:
postid, message, forum.id, forum.name
从 ngrx 示例应用程序我了解到获取论坛数据的方法是:
- 添加selectedForumId到论坛状态
- 获取 post 时:调度事件以将 selectedForumId 更新为 post 的论坛 ID
- select 论坛数据 selectedForumId
在代码中:
home.component.ts:
ngOnInit() {
this.store.dispatch(new postActions.GetAllPostsAction());
this.posts$ = store.select(fromReducers.getAllPosts);
}
home.component.html:
<post *ngFor="let post of (posts$|async)" [post]="post"></post>
post.component.ts:
@Input() post: Post;
ngOnInit() {
this.store.dispatch(new forumActions.SelectForumAction(this.post.forumId));
this.forum$ = this.store.select(fromReducers.getSelectedForum);
}
forum.reducer.ts:
export interface State extends EntityState<Forum> {
selectedForumId: number | null;
};
export function reducer(state = initialState, action: ForumActions): State {
switch (action.type) {
case ForumActionTypes.SELECT_FORUM:
return {
...state,
selectedForumId: action.payload,
};
...
export const getSelectedForumId = (state: State) => state.selectedForumId;
reducers/index.ts:
export const selectForumState = createFeatureSelector<fromForum.State>('forums');
export const selectForumEntities = createSelector(selectForumState, fromForum.selectForumEntities);
export const selectedForumId = createSelector(selectForumState, fromForum.getSelectedForumId);
export const getSelectedForum = createSelector<State, any, any, Forum>(selectForumEntities, selectedForumId,
(entities, id) => entities[id]
);
问题 -
我对这种方法的问题是,如果我在一个页面中有 10 个 post,这意味着我将发送更新 selectedForumId 10 次的操作,但感觉不对。
有没有我可以使用的更好的实践方法,它仍然会利用 createSelector 的优势来创建记忆 selector?
1) 在我的例子中,当我从我的商店中获取数据时,我做了一些错误的做法,里面应该是一个愚蠢的组件 (post.component.ts)
2) 第一个解决方案
起初我有这个问题: @Ngrx/store: how to query models with relationships
评论中有对以下文章的 link:https://netbasal.com/querying-a-normalized-state-with-rxjs-in-angular-71ecd7ca25b4
这篇文章让我实现了解决方案:
posts.service.ts:
getPostsViewModel(posts$: Observable<Post[]>, users$: Observable<User[]>, forums$: Observable<Forum[]>): Observable<PostView[]> {
return Observable.combineLatest(posts$, users$, forums$, (posts, users, forums) => {
return posts.map(post => Object.assign({}, post, {
user: users.find(user => user.id === post.userId),
forum: forums.find(forum => forum.id === post.forumId)
}))
});
}
home.component.ts:
ngOnInit() {
this.store.dispatch(new postActions.GetAllPostsAction());
this.postsView$ = this.postService.getPostsViewModel(
this.store.select(fromReducers.getAllPosts),
this.store.select(fromReducers.getAllUsers),
this.store.select(fromReducers.getAllForums));
}
这个解决方案有效!
3) 第二种解法
但我仍然对我没有使用 createSelector 记忆功能感到困扰。有了这种新方法,我试图思考如何将其应用到 createSelector 中,答案如下:
reducers/index.ts:
export const selectPostIds = createSelector(selectPostState, fromPost.selectPostIds);
export const selectPostEntities = createSelector(selectPostState, fromPost.selectPostEntities);
export const selectedForumId = createSelector(selectForumState, fromForum.getSelectedForumId);
export const getAllUsers = createSelector<State, any, any, User[]>(selectUserEntities, selectUserIds,
(entities, ids) => ids.map(id => entities[id])
);
export const getAllForums = createSelector<State, any, any, Forum[]>(selectForumEntities, selectForumIds,
(entities, ids) => ids.map(id => entities[id])
);
export const getAllPosts = createSelector<State, any, any, any, any, PostView[]>(selectPostEntities, selectPostIds, getAllUsers, getAllForums,
(entities, ids, users, forums) => {
let posts = ids.map(id => entities[id]);
return posts.map(post => Object.assign({}, post, {
user: users.find(user => user.id === post.userId),
forum: forums.find(forum => forum.id === post.forumId)
}));
}
);
home.component.ts:
ngOnInit() {
this.store.dispatch(new postActions.GetAllPostsAction());
this.posts$ = this.store.select(fromReducers.getAllPosts);
}
现在我在 createSelector() 中有了解决方案!
我还是想知道 -
我的实现中的记忆过程是否足够好?
创建一个名为的方法不是更好吗:
getForumFromListOfForums(论坛:论坛[], forumId)
并使用 loadsh 来记忆它?
然后从 post.component.ts 转到它,让每个 post 请求它的论坛?
如果论坛在响应被记忆之前已经被问过,那么将是 O(1)。