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

Angular 15迁移Firestore后组件首次加载不渲染问题求助

问题:Angular 15 + Firestore 首次筛选后画廊不渲染

我使用Angular 15.2.0开发相册项目,此前基于Angular的InMemoryDBService测试完全正常。用户选择筛选条件后,画廊服务会查询匹配的照片并返回Observable,组件订阅后将photos属性赋值为返回结果。

模板代码

<app-filter-select
  *ngIf="!filtersChosen && filterList.length !== 0"
  [filters]="filterList"
  (Submitted)="setGallery($event)"
></app-filter-select>
<div *ngIf="filtersChosen">
  <div class="center-screen" *ngIf="loading">
    <mat-spinner class="center-screen"></mat-spinner>
  </div>
  <mat-grid-list
    *ngIf="photos && photos.length > 0"
    class="gallery-container"
    gutterSize="1em"
    cols="3"
  >
    <mat-grid-tile
      class="photo-holder"
      *ngFor="let photo of photos"
      [colspan]="1"
      [rowspan]="1"
    >
      <a [routerLink]="['/photos', photo.id]">
        <app-gallerycard
          (loaded)="onLoad()"
          [hidden]=loading
          [photo]="photo"
          style="display: flex; justify-content: center"
        ></app-gallerycard>
      </a>
    </mat-grid-tile>
  </mat-grid-list>
</div>

网格瓦片的[hidden]属性绑定到loading属性,所有照片加载完成后该属性会变为false。

问题现象

迁移到Firestore生产环境后出现异常:提交筛选条件后,subscribe回调中为组件photos属性赋值,但<mat-grid-list>完全不渲染,loading属性始终不变,加载spinner持续显示,照片无法展示。仅首次导航到画廊页面时会出现此问题,再次点击画廊导航按钮或切换页面返回后,照片能正常渲染。我未修改画廊组件,仅改动了画廊服务的getPhotosWithFilterArray()方法,将查询源从InMemoryDB改为Firestore。

组件筛选提交逻辑

photos?: Photo[];
setGallery(data: any) {
  this.filtersChosen = true;
  const filterNames: string[] = [];
  data.filters.forEach((f: Genre) => {
    filterNames.push(f.name.toUpperCase());
  });
  this.galleryService
    .getPhotosWithFilterArray(filterNames)
    .subscribe((photos) => {
      this.photos = photos;
    });
}

画廊服务实现

getPhotosWithFilterArray(filters: Array<string>): Observable<Photo[]> {
  const photosRef = collection(this.firestore, 'photos');
  const filteredPhotos = query(photosRef, where('genre', 'in', filters));
  return collectionData(filteredPhotos).pipe(
    tap((p) => console.log(p as Photo[])),
    map((p) => p as Photo[]),
    catchError(this.handleError<Photo[]>('getPhotosWithFilterArray', []))
  );
}

已尝试的解决方法

  • 将<mat-grid-list>的*ngIf改为绑定photosFetched属性,并在subscribe回调中将其设为true
  • 实现ngDoCheck(),在photos值变化时将photosFetched设为true
  • 实现ngOnChanges(),在捕获到变更时将photosFetched设为true

尚未尝试使用async管道渲染Observable数据,因为组件其他部分依赖photos为数组而非Observable;也考虑过将<app-filter-select>组件抽离到其他页面,但InMemoryDB环境下该逻辑正常,暂不采用此方案。

再次强调:仅首次设置筛选条件时出现问题,迁移到Firestore前无此异常。photos已绑定有效数组,photosFetched值也已更新,但均无法触发模板的状态变更。


更新:临时解决方案

未能彻底解决问题,推测可能是Angular变更检测的Bug。找到一个临时可行的方案:
画廊服务改为从Firestore获取整个文档集合,不再返回Observable流,而是通过getPhotos()函数设置私有_photos数组。网站加载图片前,通过以下方法检查数组是否初始化:

photosInitializedYet() { return this._photos.length !== 0 }

由于Firestore查询是异步操作,会等待getPhotos()的响应,*ngFor元素会等到带有文件路径的Photo对象存在后再渲染。此方案需在服务中保存Firestore数据库的静态副本,虽不优雅但能正常工作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 02:17:15