NgRx4+Angular5下关联获取指定ID数据的优化方案问询
优化NgRx中帖子关联论坛数据的获取方案
你的问题很典型——用全局的selectedForumId来匹配帖子所属论坛,确实会导致重复dispatch和状态冲突的问题,尤其是当页面有多个帖子时,不仅冗余,还可能因为状态被覆盖显示错误的论坛信息。下面是一个更优雅的方案,完全保留createSelector的memoization特性,同时避免不必要的action dispatch:
核心思路:创建带参数的Selector工厂函数
我们不需要依赖全局的selectedForumId,而是直接为每个帖子创建一个根据forumId获取对应论坛的selector,利用NgRx的memoization机制缓存结果,避免重复计算。
步骤1:定义带参数的Selector
在reducers/index.ts中,新增一个返回selector的工厂函数,接受forumId作为参数:
// reducers/index.ts import { createFeatureSelector, createSelector } from '@ngrx/store'; import * as fromForum from '../forum.reducer'; export const selectForumState = createFeatureSelector<fromForum.State>('forums'); export const selectForumEntities = createSelector(selectForumState, fromForum.selectForumEntities); // 带参数的Selector工厂:根据forumId获取对应的论坛实体 export const getForumById = (forumId: number) => createSelector(selectForumEntities, (entities) => entities[forumId]);
步骤2:修改Post组件获取论坛数据
去掉原来的SelectForumAction dispatch逻辑,直接通过上面的selector获取当前帖子对应的论坛:
// post.component.ts import { Component, Input, OnInit } from '@angular/core'; import { Store } from '@ngrx/store'; import { Observable } from 'rxjs'; import { Post } from '../models/post.model'; import { Forum } from '../models/forum.model'; import { getForumById } from '../reducers'; @Component({ selector: 'post', templateUrl: './post.component.html' }) export class PostComponent implements OnInit { @Input() post: Post; forum$: Observable<Forum>; constructor(private store: Store) { } ngOnInit() { // 直接传入当前帖子的forumId,获取对应的论坛数据 this.forum$ = this.store.select(getForumById(this.post.forumId)); } }
步骤3:在模板中展示关联数据
用async管道直接订阅论坛数据即可:
<!-- post.component.html --> <div class="post-card"> <h4>Post #{{post.id}}</h4> <p>{{post.message}}</p> <div class="forum-info" *ngIf="forum$ | async as forum"> <span>所属论坛: {{forum.name}} (ID: {{forum.id}})</span> </div> </div>
为什么这个方案更好?
- 避免冗余的Action Dispatch:不需要为每个帖子触发
SELECT_FORUM,减少Store的不必要更新 - 无状态冲突:每个帖子独立获取自己的论坛数据,不会因为全局
selectedForumId被覆盖而显示错误信息 - 保留Memoization优势:
selectForumEntities是memoized的,只有当Forums状态变化时才会重新计算- 对于同一个
forumId,getForumById返回的selector会缓存结果,除非该论坛实体发生变化,否则不会重复计算 - 如果多个帖子属于同一个论坛,NgRx会自动复用缓存的结果,提升性能
原方案的弊端回顾
- 全局
selectedForumId会被多个帖子组件覆盖,导致页面上的帖子可能显示错误的论坛信息(比如滚动时,后面的帖子会覆盖前面的状态) - 频繁的Action Dispatch会触发Store多次更新,导致所有依赖Forum状态的Selector重新计算,浪费性能
内容的提问来源于stack exchange,提问作者shahaf
相关产品推荐
相关产品推荐

