Javascript 脱机时发生Firestore更改时未更新NGRX状态
我有一个AngularFire应用程序,它使用AngularFire、NgRx和云Firestore作为db,在这里我启用了Javascript 脱机时发生Firestore更改时未更新NGRX状态,javascript,firebase,google-cloud-firestore,ngrx,angularfire2,Javascript,Firebase,Google Cloud Firestore,Ngrx,Angularfire2,我有一个AngularFire应用程序,它使用AngularFire、NgRx和云Firestore作为db,在这里我启用了离线持久性 我的问题是,当我在脱机时更改文档时,effect函数不会触发成功操作,因为Firestore承诺在脱机时不会得到解决,而只有在请求到达服务器后才会得到解决 目前,我正努力寻找一种在离线时用本地数据更新存储的好方法 一种方法是在加载数据之前检查fromCache标志,这样如果fromCache为true(即,我们处于脱机状态),我就可以从本地数据库而不是存储区加载
离线持久性
我的问题是,当我在脱机时更改文档时,effect函数不会触发成功操作,因为Firestore承诺在脱机时不会得到解决,而只有在请求到达服务器后才会得到解决
目前,我正努力寻找一种在离线时用本地数据更新存储的好方法
一种方法是在加载数据之前检查fromCache
标志,这样如果fromCache为true(即,我们处于脱机状态),我就可以从本地数据库而不是存储区加载数据,但在我看来这是一个肮脏的解决方法
效果
//--- 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 })))
);
*/
})
);
});
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());
}
DB服务
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));
}
当
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;
}
如果本地写入操作失败,
update
将抛出一个异常,该异常将从savePlace
转义,向调用者发出失败信号。因此,解决方案是强制更新状态,忽略更新结果(成功/错误),因为这只有在它到达服务器时才能得到解决?这取决于目标:如果您想在UI中显示什么时候写入了服务器,请在侦听器中使用promise或fromCache
/pendingWrites
标志。如果您只关心写入本地缓存的更改,则不需要执行任何这些操作。API的设计目的是让这条路变得愉快。我的目标是为用户提供无缝体验,从而在脱机时立即显示本地更改。在引入NgRx之前,我确实展示了缓存中挂起的更改。现在有了提供数据的存储,我需要直接更新它,而不查看更新调用的结果,否则我就不会有状态的本地更改。然后,我将删除建议中的承诺,并将save方法调用封装在try/catch中。让我知道结果如何。我对NgRX没有特别的经验,因此可能缺少一些映射的细微差别。我将更新我的问题,以便您也可以获得缺少的相关部分。我面临的问题是,如果我使用更新方法的promise,那么从本地缓存中获取文档不会返回所做的更改(它会返回脱机更改的第一个文档,但不会返回第二个或第三个…)。同时感谢您的帮助:)
savePlace(place): void {
this.firestoreRef.doc<T>(`places/${place.id}`).update(place)
}