ngrx用memoization方法选择特定对象id的数据

时间:2018-01-22 10:24:51

标签: angular redux ngrx

我的问题是关于ngrx4(带有angular5)。

我正在使用具有以下数据结构的应用程序:

  ngOnInit() {
    this.store.dispatch(new postActions.GetAllPostsAction());
    this.posts$ = store.select(fromReducers.getAllPosts);
  }

当我发帖子时,我也会出席它的论坛。所以一个职位代表是:

  

postid,message,forum.id,forum.name

来自ngrx示例应用程序我明白获取论坛数据的方法是:

  1. 将selectedForumId添加到论坛状态
  2. 在获取帖子时:发送事件以将selectedForumId更新为帖子的forumid
  3. 按selectedForumId
  4. 选择论坛数据

    代码:

    home.component.ts:

    <post *ngFor="let post of (posts$|async)" [post]="post"></post>
    

    home.component.html:

      @Input() post: Post;
      ngOnInit() {
        this.store.dispatch(new forumActions.SelectForumAction(this.post.forumId));
        this.forum$ = this.store.select(fromReducers.getSelectedForum);
      }
    

    post.component.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;
    

    forum.reducer.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]
    );
    

    减速器/ index.ts:

    collectionView

    问题 -

    我的问题是,如果我在一个页面中有10个帖子,这意味着我会调度更新selectedForumId 10次的操作,感觉不对。

    我可以使用哪种更好的练习方法,仍然会使用创建memoized选择器的createSelector的优势吗?

1 个答案:

答案 0 :(得分:1)

1)在我的例子中,当我从我的商店中获取数据时,我做了一些不好的做法,这应该是一个愚蠢的组件(post.component.ts)

2)第一个解决方案

起初我提出了这个问题: @Ngrx/store: how to query models with relationships

评论中的内容是指向以下文章的链接: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的memoization功能。我试着想一想如何将这个应用到createSelector中,这就是答案:

减速器/ 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转到它并让每个帖子询问它的论坛?

如果在回复被记忆之前已经询问了论坛,那么就是O(1)。