【问题标题】:Firebase firestore onSnapshot - Get real-time updates after initial data query using promisesFirebase firestore onSnapshot - 在使用 Promise 进行初始数据查询后获取实时更新
【发布时间】:2019-06-21 06:24:05
【问题描述】:

为了显示加载进度,我试图在初始获取时将我的 onSnapshot 调用包装在一个 Promise 中。数据正在正确加载,但实时更新无法正常运行。

有没有办法使用 onSnapshot 方法实现这种类型的功能?

这是我最初的数据抓取。在实现 Promise 包装器之前,实时更新功能正常:

const [heroesArr, setHeroesArr] = useState([]);
const db = firebase.firestore();
const dbError = firebase.firestore.FirestoreError;

useEffect(() => {
    const promise = new Promise((resolve, reject) => {
      db.collection("characterOptions")
        .orderBy("votes", "desc")
        .onSnapshot(coll => {
          const newHeroes = [];
          coll.forEach(doc => {
            const {
              name,
              votes
            } = doc.data();
            newHeroes.push({
              key: doc.id,
              name,
              votes
            });
          });
          if(dbError) {
             reject(dbError.message)
             } else {
             resolve(newHeroes);
            }
        });
    });
    promise
      .then(result => {
        setHeroesArr(result);
      })
      .catch(err => {
        alert(err);
      });
  }, [db]);

再次,数据正在加载到 DOM,但实时更新无法正常运行。

【问题讨论】:

    标签: javascript reactjs firebase google-cloud-firestore


    【解决方案1】:

    onSnapshot 与 Promise 并不真正兼容。 onSnapshot 侦听器无限期地侦听,直到您删除侦听器。当工作完成时,Promise 只会解决一次。将 onSnapshot (直到你说它才结束)与一个 promise 结合起来是没有意义的,它会在工作确定完成时解决。

    如果您只想获取一次查询的内容,只需 get() 而不是 onSnapshot。当所有数据都可用时,这将返回一个承诺。有关详细信息,请参阅documentation

    【讨论】:

      【解决方案2】:

      以下是我对您的代码的看法:当您的组件挂载时,您的承诺会通过 useEffect 执行一次,这就是您设置状态的地方。但是,通过 onSnapshot 监听器的后续更新不会更改 db 引用,因此不会再次触发 useEffect,因此不会再次执行 promise,因此不会再次设置状态。

      当您收到快照更新时将执行的唯一代码是 .onSnapshot() 中的回调函数。

      要解决此问题,我认为您可以尝试以下方法(老实说,我不确定它是否会起作用,但值得一试):

      1. 创建一个变量来跟踪初始负载:let isInitialLoad = true;
      2. 在你的 promise.then() 中,添加 isInitialLoad = false;
      3. 在您的 .onSnapshot() 中,添加 if (!isInitialLoad) setHeroesArr(newHeroes); - 这样,在初始加载时 setHeroesArr 会在 promise 上执行,但在快照更新时 setHeroesAss 会在 .onSnapshot() 回调中执行

      这种方法的缺点是 setHeroesArr 将在快照更改时立即被调用,而不是被包装在 Promise 中。

      希望这会有所帮助!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-06-11
        • 2020-06-14
        • 2021-10-31
        • 1970-01-01
        • 1970-01-01
        • 2020-11-30
        • 2020-10-18
        • 2019-03-28
        相关资源
        最近更新 更多