在 for 循环中使用 firebase onSnapshot()?

Use firebase onSnapshot() in for loop?

下面的代码适用于从 firestore 获取我的数据。我正在尝试将其更新为使用 onSnapshot() 而不是 get()。也许我的困惑的核心是 onSnapshot() 没有 return 承诺,我试过将侦听器添加到数组中,但数据似乎没有得到更新。如何迭代 onSnapshot()for 循环并呈现结果?

const [activityDataArray, setActivityDataArray] = useState([]);
const userActivityIds = userData.activities

useEffect(() => {
    let promises = [];
    for (const activityId of userActivityIds) {
        promises.push(getFirestoreData("activities", activityId));
    }
    Promise.all(promises).then(response => setActivityDataArray(response));
}, [userActivityIds]);

更新代码: 当我 console.log() 数组有我的数据时,但我认为这是 chrome 显示新信息的开发工具的一个技巧。我想当我调用 setActivityDataArray 时,它是 运行 它在一个空数组上,然后它再也不会被调用。因此,除非我切换到我的应用程序中的不同选项卡并返回,否则数据不会呈现。然后它正确呈现(所以我知道数据很好,这只是一个呈现问题)。我想我需要在 onSnapshot() 内重新渲染,但我该如何正确地执行此操作?

const [activityDataArray, setActivityDataArray] = useState<any>([]);
const userActivityIds: string[] = userData.activities

useEffect(() => {
    let activityDataArrayDummy: any[] = []
    for (const i in userActivityIds) {
        firebase.firestore().collection("activities").doc(userActivityIds[i])
            .onSnapshot((doc) => {
                activityDataArrayDummy[i] = doc.data();
            });
    }
    console.log("activityDataArrayDummy", activityDataArrayDummy)
    setActivityDataArray(activityDataArrayDummy);
}, [userActivityIds]);

只需在循环中调用 onSnapshot() 即可。

import { doc, onSnapshot } from "firebase/firestore";

for (const activityId of userActivityIds) {
  // get reference to document
  const docRef = doc(db, "activities", activityId)
  
  onSnapshot(docRef, (snapshot) => {
    // read and render data from snapshot
  })
}

但是,如果您需要取消订阅任何听众,那么您可能需要存储 Unsubscribe function returned by onSnapshot 州内某处。


以防万一 userActivityIds 中的项目不超过 10 个,那么您可以使用 onSnapshot()Query 代替:

const q = query(collection(db, "activities"), where(documentId(), "in", userActivityIds));

onSnapshot(q, (querySnapshot) => {
  // ... 
})

我同意了。显然不能保证反应中的状态会被更新,因此使用更新数据设置状态的正确方法是使用回调函数。

https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous

const [activityDataObj, setActivityDataObj] = useState({})
const userActivityIds: string[] = userData.activities

useEffect(() => {
    for (const i in userActivityIds) {
        firebase.firestore().collection("activities").doc(userActivityIds[i])
            .onSnapshot((doc) => {
                setActivityDataObj((activityDataObj) => {
                    return {...activityDataObj, [userActivityIds[i]]: doc.data()}
                })
            });
    }
}, [userActivityIds]);