Circunstancias: para mi proyecto de aplicación que usa una base de datos en tiempo real, intento cargar datos de todas las máquinas asociadas con el usuario. Las máquinas que debe ver el usuario dependen de la empresa relacionada (cid) y qué máquinas pertenecen a esa empresa.
Problema: he usado los documentos de Firebase v9 tanto como ha sido posible y he creado el código que puedes ver a continuación. Sin embargo, este código solo devuelve las máquinas correctas después de 3 renderizaciones. Parece que cada comando onValue solo devuelve algo después de volver a renderizar. ¿Puede alguien explicarme una forma en que puedo obtener los datos completos sin volver a renderizar la pantalla a la fuerza? Ya intenté usar el comando get de forma asíncrona, pero esto no pareció cambiar nada.
useEffect(() => { const auth = getAuth(); const db = getDatabase(); const userRef = ref(db, "users/" + auth.currentUser.uid + "/cid"); onValue(userRef, (snapshot) => { const cid = snapshot.val(); setCid(cid, true); }); const machinesRef = ref(db, "companies/" + cid + "/machines"); onValue(machinesRef, (snapshot) => { const fetchedData = []; snapshot.forEach((childSnapshot) => { const childKey = childSnapshot.key; const childData = childSnapshot.val(); const parsRef = ref(db, "machines/" + childKey); onValue(parsRef, (snapshot) => { const parData = snapshot.val(); fetchedData.push( new Machine( childKey, cid, childData.type, childData.creation, parData.temperature ) ); }); }); setData(fetchedData); }); console.log(cid); # Outputted in the results section console.log(data); # Outputted in the results section }, []); Resultados:
renderizar 1:
null Array []renderizar 2:
cid # This is correct Array []renderizar 3:
cid Array [ Machine { "companyId": "cid", "creation": "creation", "id": "23rff3345GRR", "temperature": 99, "type": "type", }, Machine { "companyId": "cid", "creation": "creation", "id": "3454egGR3", "temperature": 2, "type": "type", }, ]Deberá mover la llamada a setData al controlador onValue :
onValue(machinesRef, (snapshot) => { const fetchedData = []; snapshot.forEach((childSnapshot) => { const childKey = childSnapshot.key; const childData = childSnapshot.val(); const parsRef = ref(db, "machines/" + childKey); onValue(parsRef, (snapshot) => { const parData = snapshot.val(); fetchedData.push( new Machine( childKey, cid, childData.type, childData.creation, parData.temperature ) ); setData(fetchedData); // 👈 }); }); Si lo deja fuera de las devoluciones de llamada, se ejecutará antes de que se llame a fetchedData.push(...) . La forma más fácil de verificar esto es estableciendo puntos de interrupción en ambas líneas y ejecutándolos en un depurador, o agregando algo de registro y verificando el orden de la salida.
Para obtener una explicación más detallada sobre esto, consulte: ¿Por qué Firebase pierde la referencia fuera de la función once ()? (anterior a v9, pero el comportamiento es exactamente el mismo independientemente de la versión)