You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NgRx中派生ItemVM ViewModel时如何确保依赖数据已加载?

NgRx视图模型派生:确保数据加载完成的解决方案

核心概念澄清

你创建的selectItemViewModel是一个memoized选择器函数,本身并非Observable,但当你在组件中通过store.select(selectItemViewModel)调用它时,会返回一个Observable<ItemVM[]>。这个Observable会自动监听Store中users、categories、items的状态变化,只有当依赖的状态更新时,才会重新计算并发出新的派生视图模型。


解决数据未加载完成的问题

1. 先修复Selector的潜在崩溃风险

当前的Selector中,users.find()或categories.find()可能返回undefined(比如数据未加载完成时),直接访问.name会抛出运行时错误。先给映射逻辑添加空值保护:

export const selectItemViewModel = createSelector(
  selectUsers,
  selectCategories,
  selectItems,
  (users, categories, items) => {
    return items.map(i => ({
      id: i.id,
      userName: users.find(u => u.id === i.userId)?.name || '未知用户',
      categoryName: categories.find(c => c.id === i.categoryId)?.name || '未知分类'
    } as ItemVM));
  }
);

2. 确保所有数据加载完成后再渲染

有两种常用方案控制渲染时机:

方案一:通过Store维护加载状态

在对应的State结构中添加加载完成标记(如loaded布尔值),并创建对应的选择器:

// 示例State结构
interface AppState {
  users: { list: User[], loaded: boolean };
  categories: { list: Category[], loaded: boolean };
  items: { list: Item[], loaded: boolean };
}

// 对应加载状态的选择器
export const selectUsersLoaded = createSelector(
  selectUsersState,
  state => state.loaded
);
export const selectCategoriesLoaded = createSelector(
  selectCategoriesState,
  state => state.loaded
);
export const selectItemsLoaded = createSelector(
  selectItemsState,
  state => state.loaded
);

// 组合判断所有数据是否加载完成
export const selectAllDataLoaded = createSelector(
  selectUsersLoaded,
  selectCategoriesLoaded,
  selectItemsLoaded,
  (usersLoaded, categoriesLoaded, itemsLoaded) => 
    usersLoaded && categoriesLoaded && itemsLoaded
);

然后在组件中合并Observable,等待全部数据加载完成后再处理视图模型:

import { combineLatest } from 'rxjs';

// 组件类中
itemVMs: ItemVM[] = [];
isLoading = true;

ngOnInit() {
  combineLatest([
    this.store.select(selectItemViewModel),
    this.store.select(selectAllDataLoaded)
  ]).subscribe(([vms, allLoaded]) => {
    this.isLoading = !allLoaded;
    if (allLoaded) {
      this.itemVMs = vms;
    }
  });
}

模板中根据状态切换显示:

<div *ngIf="isLoading">加载中...</div>
<ul *ngIf="!isLoading">
  <li *ngFor="let vm of itemVMs">
    ID: {{vm.id}} | 用户: {{vm.userName}} | 分类: {{vm.categoryName}}
  </li>
</ul>
方案二:在组件中过滤Observable

如果没有维护加载状态,也可以通过过滤操作,等待三个数据源都返回有效数据:

import { filter } from 'rxjs/operators';

// 组件类中
ngOnInit() {
  this.store.select(selectItemViewModel).pipe(
    filter(vms => {
      // 间接判断依赖数据是否加载完成
      return vms.length > 0 && vms.every(vm => vm.userName !== '未知用户' && vm.categoryName !== '未知分类');
    })
  ).subscribe(vms => {
    this.itemVMs = vms;
    this.isLoading = false;
  });
}

关键总结

  • NgRx选择器本身不是Observable,但通过store.select()调用后会返回响应式的Observable,自动追踪状态变化。
  • 必须处理数据未加载时的空值情况,避免运行时错误。
  • 通过维护加载状态或过滤Observable,可以确保只有在所有依赖数据就绪后,才渲染派生的视图模型。

内容的提问来源于stack exchange,提问作者Lou

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 10:25:21