【问题标题】:Can Cloud Firestore onSnapshot() only trigger on changes, and not get the initial state?Cloud Firestore onSnapshot() 是否只能在更改时触发,而不是获取初始状态?
【发布时间】:2019-03-28 01:38:36
【问题描述】:

documentation 说:

您可以使用 onSnapshot() 方法收听文档。使用您提供的回调的初始调用会立即使用单个文档的当前内容创建文档快照。然后,每次内容更改时,另一个调用会更新文档快照。

我只希望我的监听器在数据更改时触发。我不希望它在应用程序加载时触发,以获取数据的初始状态。有什么建议吗?

【问题讨论】:

  • 我会喜欢这个功能的!

标签: firebase google-cloud-firestore


【解决方案1】:

没有。每当您使用 onSnapshot 时,都会进行初始调用以立即获取数据,然后监听更改。

但您可以使用 firebase 提供的以下属性处理其中的逻辑,以检测它是初始调用还是更新触发器。

  db
  .collection("pets")
    .doc(petId)
    .onSnapshot(
      snapshot => {
        let data = snapshot.data()
          // either edit, update or delete
          if (snapshot.metadata.hasPendingWrites) { 
            if (snapshot.exists) {
              // edit or create logic
            }
            else{
             // delete logic
            }
        }
      
      },
      err => {
        console.log(err)
      }
    )

【讨论】:

    【解决方案2】:

    对我也有用的是检查 document.readystate,然后选择对快照更改采取行动。像这样-

    db.collection("collectionName").onSnapshot( (snapshot) => {
        console.log(snapshot.docChanges())
        if( ["loaded","interactive", "complete"].indexOf(document.readyState) >=0 ){
            <-----Your code to act on the snapshot changes---->
    
    }
    
    

    基于此处的 readystate 属性文档 - https://www.w3schools.com/jsref/prop_doc_readystate.asp

    【讨论】:

      【解决方案3】:

      在阅读了第一个和第二个解决方案后,我提出了一个似乎可行的解决方案。 首先将变量初始化为true,然后在onSnapshot() 方法中检查此变量是否为true,如果是,则将其更改为false,否则编写检索数据算法。像这样的:

      var initState = true;
      
      let observer = records.onSnapshot(docSnapshot => {
      
          console.log(`Received doc snapshot`);
      
          if (initState) {
              initState = false;
          } else {
              if (!docSnapshot.docChanges().empty) {     
                  docSnapshot.docChanges().forEach(function (change) {
                     //Write here wahtever you want
      
                  });
              }
          }
      
      }, err => {
          console.log(`Encountered error: ${err}`);
      });
      

      【讨论】:

      • 注意:这个解决方案非常肤浅,它所做的只是使用 (if.​​..else) 语句忽略第一次获取数据。 OP 问题的唯一解决方案是等待 firestore 团队给我们一个 API,它可以使初始快照成为可选的。
      【解决方案4】:

      Firestore 侦听器按其自己的顺序加载,并且“onSnapshot”事件必须始终在初始状态下首先执行。但是,您可以通过添加初始状态变量来处理该行为,例如:

      var initState = true;
      db.collection('col').doc('id').onSnapshot(....
      

      然后您可以在函数内部验证您不想在应用程序启动时运行的代码。

      var initState = true;
      db.collection('col').doc('id').onSnapshot(....
      if(!initState){ // if is not initial state
         //your code
      }
      

      并且在应用程序启动后你必须将 initState 更改为 false 并添加一个睡眠/超时功能(因为它可能有一个意外的异步负载)

      var initState = true;
      db.collection('col').doc('id').onSnapshot(....
      if(!initState){ // if is not initial state
         //your code
      }
      
      setTimeout(function () { // cause onSnapShot executes first
         initState = false;
      }, 2000);
      

      【讨论】:

        【解决方案5】:

        Firestore 侦听器不是这样工作的。您将始终收到与获取或查询相关的文档,然后在此之后更新,只要监听器仍然添加。没有仅接收增量的模式。

        如果您只想接收某些数据,您可能想弄清楚如何查询它,例如,通过添加时间戳字段并让客户端仅查询自前一段时间以来发生更改的文档。

        【讨论】:

        • 如果有忽略初始状态的能力就好了。在我的应用程序中,我正在与 Firebase 同步数据,并将其存储在 CoreData 中以供我的应用程序进一步使用。令人讨厌的是,在应用程序启动时,我从侦听器获取所有数据,甚至是我已经存储的数据。我现在需要找到一种方法来忽略第一次发布。我们是否保证所有本地数据(初始状态)始终有 1 个响应,其中不包含来自服务器的任何新信息?如果是这样,我可以完全忽略听者的一个响应来实现我想要的功能。
        • 您不能忽略数据。您可以改为构建一个只返回您想要的数据的查询。如果你不能构造这样的查询,那么你就不走运了。
        • 在阅读的同时获得一个 Etag 会很好,然后下次你阅读同一个集合时,你可以提供你的 Etag 为“这就是我已经拥有的”,如果有更新的 Etag在 Firestore 中,它仅在下一个查询中发送增量。
        • 感谢您对 SO 的官方支持,Doug 先生。我对您的陈述“Firestore 侦听器不那样工作”有疑问......文档指出,这种隐式行为是为了方便使用初始状态填充 UI 而设计的。在那种情况下,用户应该可以选择是否接收初始状态,对吧?像ListenerOptions.getInitialState()ListenerOptions.ignoreInitialState() 这样的字段将使onSnapshot() 方法更加灵活,就像'SetOptions.merge()' 一样! Firebaser,这是一个合理的要求吗? :D
        • @varun 当然,您可以随时向 Firebase 支持提出功能请求。 support.google.com/firebase/contact/support
        猜你喜欢
        • 2020-03-21
        • 1970-01-01
        • 2018-10-27
        • 2020-02-04
        • 1970-01-01
        • 1970-01-01
        • 2021-08-12
        • 1970-01-01
        相关资源
        最近更新 更多