El siguiente código funciona para obtener mis datos de firestore. Estoy tratando de actualizar esto para usar onSnapshot() en lugar de get() . Tal vez el núcleo de mi confusión es onSnapshot() no devuelve una promesa y he intentado simplemente agregar los oyentes en una matriz, pero parece que los datos no se actualizan. ¿Cómo itero sobre un bucle for de onSnapshot() y renderizo los resultados?
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]); CÓDIGO ACTUALIZADO: cuando hago console.log() la matriz tiene mis datos, pero creo que esto es un truco con las herramientas de desarrollo de Chrome que muestran nueva información. Creo que cuando llamo a setActivityDataArray lo está ejecutando en una matriz vacía y luego nunca más se vuelve a llamar. Por lo tanto, los datos no se procesan a menos que cambie a una pestaña diferente en mi aplicación y regrese. Luego se procesa correctamente (así que sé que los datos son buenos, es solo un problema de procesamiento). Creo que necesito volver a renderizar dentro de onSnapshot() pero, ¿cómo hago esto correctamente?
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]);Simplemente llamar a onSnapshot() en un bucle debería hacerlo.
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 }) } Sin embargo, si alguna vez necesita cancelar la suscripción de cualquiera de los oyentes, es posible que deba almacenar la función Unsubscribe devuelta por onSnapshot en algún lugar del estado.
En caso de que tenga 10 elementos o menos en userActivityIds , puede usar onSnapshot() con una Query en su lugar:
const q = query(collection(db, "activities"), where(documentId(), "in", userActivityIds)); onSnapshot(q, (querySnapshot) => { // ... })Fui con esto. Aparentemente, no se garantiza que el estado en reacción se actualice, por lo que la forma correcta de configurar el estado con datos actualizados es usar una función de devolución de llamada.
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]);