如何从ngrx entity中无需id获取单例实体 认证用户场景实现是否合理
现有代码错误原因
- 组件中
this.store.select(fromUser.selectAll)[0]写法错误:store.select返回的是Observable流对象,不是普通数组,直接索引取值无法拿到数据。 - 最后一段代码中调用
entities.take(1)错误:entities是entity selector返回的普通数组,不是Observable,不存在rxjs的take方法,自然会报错。
正确实现方式
你之前写的自定义selector逻辑方向是对的,调整写法即可:
1. 修正selector定义
// 去掉多余的高阶函数包裹,直接导出selector实例 export const selectAuthenticatedUser = createSelector( fromUser.selectAll, (users: User[]) => users.length > 0 ? users[0] : null );
2. 组件中调用selector
//in app.component user$ : Observable<User | null>; constructor(private store : Store<AppState>) {} ngOnInit() { // 直接选择自定义selector this.user$ = this.store.select(selectAuthenticatedUser); this.store.dispatch(userActions.getUser()); }
UI层直接用async管道订阅user$即可渲染数据,比如{{ (user$ | async)?.username }}。
问题答疑
- 无需关联id取出单例对象的方法:上面的实现就是可行方案,因为你的
user切片最多只会存储1条已认证用户数据,直接取selectAll返回数组的第一个元素即可,完全不需要提前知道用户id。 - 是否违背entity设计初衷:不算错误,但确实不是entity的典型适用场景。ngrx entity本身是为了处理同类型实体的集合场景(比如用户列表、商品列表),单例场景用entity会有冗余逻辑。不过如果你的项目其他模块都统一使用entity规范,为了保持代码风格一致这么用完全没问题,属于可接受的实现。
可选优化方案
如果想更贴合entity的设计规范,可以在user切片的state中额外加一个字段存储当前认证用户的id:
// user state定义 export interface UserState extends EntityState<User> { authenticatedUserId: string | null; }
在reducer处理登录/拉取用户信息的action时,除了用entity adapter的addOne方法写入用户数据,同时把authenticatedUserId赋值为当前用户的id。之后selector可以这么写:
// 先定义取authenticatedUserId的基础selector export const selectAuthenticatedUserId = createSelector( selectUserState, (state: UserState) => state.authenticatedUserId ); export const selectAuthenticatedUser = createSelector( fromUser.selectEntities, selectAuthenticatedUserId, (userEntities, userId) => userId ? userEntities[userId] : null );
这种写法扩展性更强,就算后续需要在这个切片里存储多个用户数据也不会出问题。
内容的提问来源于stack exchange,提问作者breadman0
相关产品推荐
相关产品推荐

