【问题标题】:NGRX state not updated when Firestore changes occur while offline离线时发生 Firestore 更改时,NGRX 状态未更新
【发布时间】:2021-03-10 14:11:01
【问题描述】:

我有一个 Angular 应用程序,使用 AngularFireNgRxCloud Firestore 作为数据库,我在其中启用了 @ 987654321@.

我的问题是,当我在离线时更改文档时,效果函数不会触发成功操作,因为 Firestore 承诺在离线时不会被解析,而只有在请求到达服务器后才会解析。

目前,我一直在努力寻找一种在离线时使用本地数据更新商店的好方法。

一个想法可能是在加载数据之前检查fromCache 标志,这样如果 fromCache 为真(即我们离线)我可以从本地数据库而不是存储加载数据,但看起来对我来说就像一个肮脏的解决方法。

效果

//--- Effect triggered to load document in the home page ----
  firstSet$ = createEffect(() => {
    return this.actions$.pipe(
      ofType(PlacesActions.loadFirstPlaces),
      switchMap(() => {
        return this.placeService.getFirstSet().pipe(
          map((places) => {    
            return PlacesActions.loadFirstPlacesSuccess({ places });
          }),
          catchError((error) => of(PlacesActions.loadFirstPlacesFailure({ error }))),
          takeUntil(this.subService.unsubscribe$)
        );
      })
    );
  });


//--- Effect triggered when a document is updated ----
  updatePlace$ = createEffect(() => {
    return this.actions$.pipe(
      ofType(PlacesActions.updatePlace),
      concatMap((action) => {
        // ----- Below the NEW code, without promise ----
      try {
            this.placeService.savePlace(action.place);
            this.router.navigate(['/home']);
            return of(PlacesActions.updatePlaceSuccess({ place: action.place }));
          }
          catch(error) {
            return of(PlacesActions.updatePlaceFailure({ error }))
          }

        /*
        // ----- Below the old code ----
        return from(this.placeService.savePlace(action.place))
          .pipe(
            map((place: Place) => {
              this.router.navigate(['/home']);
              return PlacesActions.updatePlaceSuccess({ place });
            }),
            catchError((error) => of(PlacesActions.updatePlaceFailure({ error })))
          );
         */
        })
    );
  });

数据库服务

savePlace(place): void {
   this.firestoreRef.doc<Place>(`places/${place.id}`).update(place);
}

/* Old version of savePlace using Promise for the Update
async savePlace(place): Promise<void> {
    return await this.firestoreRef.doc<Place>(`places/${place.id}`).update(place);
}
*/

loadFirstPlaces(limit: number = 9,
                orderBy: OrderModel = { propName: 'modifiedOn', order: 'desc' }){

    const query = (ref: CollectionReference) => 
                   ref.orderBy(orderBy.propName, orderBy.order)
                      .limit(limit);

    return this.firestoreRef.collection<Place>('Places', query)
                            .valueChanges()
                            .pipe(shareReplay(1));
  }

首页组件

ngOnInit(): void {

    // Set the data from the store, if available there
    this.places$ = this.store.select(getAllPlaces).pipe(
      tap((data) => {
        this.places = data;            
      })
    );

   /*Dispatch load action to load data from the server or local cache.
     If I use the PROMISE approach for the update method,
     the data coming from the local cache has the old data.
     The edits done while offline are not provided.*/
   this.store.dispatch(loadFirstPlaces());
  }

【问题讨论】:

    标签: javascript firebase google-cloud-firestore ngrx angularfire2


    【解决方案1】:

    update() 调用完成时,本地缓存已更新。因此,这也是更新应用程序状态的最佳时机:

      async savePlace(place): Promise<void> {
          const result = this.firestoreRef.doc<T>(`places/${place.id}`).update(place)
          // TODO: update the state here
          return await result;
      }
    

    我什至不确定你是否应该在这里返回一个承诺。如果savePlace是返回本地操作是否成功,应该是:

      savePlace(place): void {
          this.firestoreRef.doc<T>(`places/${place.id}`).update(place)
      }
    

    如果本地写入操作失败,update 将抛出异常,该异常将从savePlace 逃逸,向调用者发出失败信号。

    【讨论】:

    • 所以解决方案是强制更新状态而忽略更新结果(成功/错误),因为只有当它到达服务器时才会解决?
    • 这取决于目标:如果您想在 UI 中显示某些内容何时写入服务器,请在侦听器中使用 promise 或 fromCache/pendingWrites 标志。如果您只关心写入本地缓存的更改,则无需执行任何这些操作。该 API 旨在让这条道路成为幸福的道路。
    • 我的目标是为用户提供无缝体验,从而在离线时立即显示本地更改。在介绍 NgRx 之前,我确实展示了缓存中的未决更改。现在有商店提供数据,我需要直接更新它,而不看更新调用的结果,否则我不会有状态的本地更改。然后,我将按照建议删除承诺,并将 save 方法调用包装在 try/catch 中。
    • 让我知道结果如何。我没有专门使用 NgRX 的经验,所以可能会遗漏一些关于映射的细微差别。
    • 我将更新我的问题,以便您也可以获得缺少的相关部分。我面临的问题是,如果我使用更新方法的承诺,那么从本地缓存中获取文档不会返回我所做的更改(它适用于第一个离线更改的文档,但不适用于第二个或第三个文档。 ..)。感谢您在此期间的帮助:)
    猜你喜欢
    • 1970-01-01
    • 2018-02-16
    • 2022-06-18
    • 2019-12-03
    • 2020-05-01
    • 1970-01-01
    • 2018-09-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多