Estoy creando una aplicación de chat con Firebase y RN. En mi código de firebase tengo una función como esta:
//all values are declared before, db is from firebase config which i do not wish to share import "firebase"; async function getPublic(dba = db) { const messages = onSnapshot(doc( /*collection name ->*/"public", dba), db => db.docs()) return messages; }¿Hay alguna manera de actualizar el valor devuelto o algo similar a eso?
En lugar de nombrar su función getPublic , considere en su lugar usePublic . O mejor aún, generalízalo para que puedas usar diferentes caminos.
Pero primero, debemos ver la definición de onSnapshot() (una CollectionReference se extiende desde Query ):
export declare function onSnapshot<T>(query: Query<T>, observer: { next?: (snapshot: QuerySnapshot<T>) => void; error?: (error: FirestoreError) => void; complete?: () => void; }): Unsubscribe; Como puede ver aquí, los messages no se devuelven desde esta función, pero una función para cancelar la Unsubscribe es (a () => void ). Entonces, para actualizar una matriz de mensajes, deberá usar useState y, dado que está usando oyentes en tiempo real, debe usar useEffect para administrar el ciclo de vida del oyente. También debe manejar los estados intermedios, como la carga, los datos erróneos y los obtenidos. Esto resulta en:
import { useEffect, useState } from 'react'; import { getFirestore, collection, onSnapshot } from "firebase/firestore"; function useMessageFeed(feed = "public", firestore = getFirestore()) { // use default firestore instance unless told otherwise // set up somewhere to store the data const [ messagesInfo, setMessagesInfo ] = useState(/* default messagesInfo: */ { status: "loading", messages: null, error: null }); // attach and manage the listener useEffect(() => { const unsubscribe = onSnapshot( // unsubscribe is a () => void collection(/* firestore instance: */ firestore, /* collection path: */ feed), { next: querySnapshot => setMessagesInfo({ status: "loaded", messages: querySnapshot.docs(), // consider querySnapshot.docs().map(doc => ({ id: doc.id, ...doc.data() })) error: null }), error: err => setMessagesInfo({ status: "error", messages: null, error: err }) } ); return unsubscribe; }, [firestore, feed]); // <-- if these change, destroy and recreate the listener return messagesInfo; // return the data to the caller }En otra parte de su código, lo usaría así:
const SomeComponent = (props) => { const { status, messages, error: messagesError } = useMessageFeed("public"); switch (status) { case "loading": return null; // hides component case "error": return ( <div class="error"> Failed to retrieve data: {messagesError.message} </div> ); } // render messages return ( /* ... */ ); }