如何使用带有redux-observable / rxjs的Firestore实时更新(onSnapshot)?

时间:2018-06-02 09:03:47

标签: reactjs firebase redux google-cloud-firestore redux-observable

我能够使用正常的Firestore查询设置redux-observable

export const getStatementsEpic = (action$, store) => {
  return action$.ofType(GET_STATEMENTS)
    .filter(() => {
      const state = store.getState()
      return state.auth.user
    })
    .mergeMap(() => {
      console.log('action', store.getState().auth.user.uid)
      const db = firebase.firestore()
      db.settings({ timestampsInSnapshots: true })
      const query = db.collection('users')
        .doc(store.getState().auth.user.uid)
        .collection('statements')
        .orderBy('uploadedOn', 'desc')
        .limit(50)
      return query.get().then(snapshot => {
        console.log('Should have gotten snapshot')
        return getStatementsSnapshot(snapshot)
      })
    })
}

但我想将其转换为实时,我尝试更改

return query.get().then(snapshot => {

return query.onSnapshot(snapshot => {

但它不起作用......我想这不是一个承诺?我该如何解决这个问题?

1 个答案:

答案 0 :(得分:1)

您是正确的,onSnapshot方法不会返回承诺。而是返回一个可用于从更改通知中取消订阅的功能。在调用该取消订阅功能之前,每次文档更改时都会调用传递给onSnapshot方法的回调。 (documentation指示还将使用当前文档内容立即调用该回调。)

可以使用onSnapshot函数将多次使用回调函数的函数fromEventPattern转换为可观察的函数。 fromEventPattern使用两个函数作为参数。您传递的第一个函数需要调用onSnapshot,并将其传递给RxJS定义的处理程序作为回调。您传递的第二个函数需要调用onSnapshot返回的取消订阅函数。当您订阅可观察对象(即在您的史诗中使用它)时,RxJS将调用第一个函数。取消订阅可观察对象时,RxJS将调用第二个函数。

以下是您的代码已更新为使用fromEventPattern和新的RxJS管道的示例:

export const getStatementsEpic = (action$, state$) => action$.pipe(
  ofType(GET_STATEMENTS),
  withLatestFrom(state$),
  filter(([action, state]) => state.auth.user),
  mergeMap(([action, state]) => {
    const db = firebase.firestore()
    db.settings({ timestampsInSnapshots: true })
    return fromEventPattern(
      handler => db.collection('users')
        .doc(state.auth.user.uid)
        .collection('statements')
        .orderBy('uploadedOn', 'desc')
        .limit(50)
        .onSnapshot(handler),
      (handler, unsubscribe) => unsubscribe(),
    ).pipe(
      map(getStatementsSnapshot),
      takeUntil(action$.pipe(
        ofType(STOP_GET_STATEMENTS),
      )),
    )
  }),
)

请注意,我已将takeUntil引入快照流。没有它(或类似的东西),快照流将永远不会结束。另一个可能的更改是使用switchMap而不是mergeMap。取消订阅的方式仅取决于您的用例。