Firebase firestore onSnapshot - 在使用 promise 进行初始数据查询后获取实时更新



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

有没有办法使用 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,但实时更新无法正常运行。

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

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

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

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

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

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

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

希望这有帮助!

最新更新