Home > Software design >  what dependencies should be used while fetching messages from firestore
what dependencies should be used while fetching messages from firestore

Time:03-20

I'm using firebase Firestore to store my chat messages in it ! everything works fine but the only problem I'm facing is that messages are not showing directly after sending them ! I used useEffect and useLayoutEffect but still nothing works ! maybe I'm not using the right dependencies

I tried using messages as dependency so after the messages get a new message it re-renders ! but still not working ?

const ChatScreen = ({ navigation, route, ...props }) => {
 const { id, chatName } = route.params;
 const [input, setInput] = useState("");
 const [messages, setMessages] = useState([]);

 useLayoutEffect(() => {
   const fetchMessages = async () => {
     const messagesSnapshop = await getDocs(
       query(
         collection(db, "chats", id, "messages"),
         orderBy("timestamp", "desc")
       )
     );
     setMessages(
       messagesSnapshop.docs.map((doc) => ({
         id: doc.id,
         data: doc.data(),
       }))
     );
   };
   fetchMessages();
 }, []);

 const sendMessage = async () => {
   Keyboard.dismiss();

   if (input !== "") {
     const docRef = doc(db, "chats", id);
     const colRef = collection(docRef, "messages");
     addDoc(colRef, {
       message: input,
       timestamp: serverTimestamp(),
       displayName: authentication.currentUser.displayName,
       email: authentication.currentUser.email,
       photoURL: authentication.currentUser.photoURL,
     });
   }
 };

 useLayoutEffect(() => {
   navigation.setOptions({
     title: chatName,
     headerBackTitle: "Chats",
     headerStyle: { backgroundColor: "#2B68E6" },
     headerTintColor: "#fff",
     headerTitleStyle: {
       fontWeight: "bold",
     },
     headerRight: () => (
       <View
         style={{
           flexDirection: "row",
           marginRight: 15,
         }}
       >
         <View style={{ marginRight: 20 }}>
           <Ionicons name="call-outline" size={24} color="white"></Ionicons>
         </View>
         <View>
           <Ionicons
             name="videocam-outline"
             size={24}
             color="white"
           ></Ionicons>
         </View>
       </View>
     ),
   });
 }, []);
 return (
   <SafeAreaView style={{ flex: 1, backgroundColor: "white" }}>
     <KeyboardAvoidingView
       behavior={Platform.OS === "android" ? "height" : "padding"}
       style={styles.container}
       keyboardVerticalOffset={90}
     >
       <>
         <ScrollView contentContainerStyle={{ paddingTop: 15 }}>
           {messages.map(({ id, data }) =>
             data.email === authentication.currentUser.email ? (
               <View key={id} style={styles.sender}>
                 <Avatar
                   rounded
                   size={30}
                   right={-5}
                   bottom={-15}
                   position="absolute"
                   source={{ uri: data.photoURL }}
                 />
                 {console.log("DATA", data)}
                 <Text style={styles.senderText}>{data.message}</Text>
                 <Text style={styles.senderName}>{data.displayName}</Text>
               </View>
             ) : (
               <View key={id} style={styles.receiver}>
                 <Avatar
                   rounded
                   size={30}
                   right={-5}
                   bottom={-15}
                   position="absolute"
                   source={{ uri: data.photoURL }}
                 />
                 <Text style={styles.receiverText}>{data.message}</Text>
                 <Text style={styles.receiverName}>{data.displayName}</Text>
               </View>
             )
           )}
         </ScrollView>
         <View style={styles.footer}>
           <TextInput
             value={input}
             placeholder="Write message here!"
             style={styles.textInput}
             onChangeText={(text) => {
               setInput(text);
             }}
           />
           <TouchableOpacity onPress={sendMessage}>
             <Ionicons name="send" size={24} color="#2B68E6" />
           </TouchableOpacity>
         </View>
       </>
     </KeyboardAvoidingView>
   </SafeAreaView>
 );
};

CodePudding user response:

getDocs fetches data once and is done. You could just run the fetchMessages function again after sending a message. Note that this isn't a very proactive solution and only fetches messages once when the component mounts and only when this client sends a message.

Example:

const ChatScreen = ({ navigation, route, ...props }) => {
  const { id, chatName } = route.params;
  const [input, setInput] = useState("");
  const [messages, setMessages] = useState([]);

  const fetchMessages = async () => {
    const messagesSnapshop = await getDocs(
      query(
        collection(db, "chats", id, "messages"),
        orderBy("timestamp", "desc")
      )
    );
    setMessages(
      messagesSnapshop.docs.map((doc) => ({
        id: doc.id,
        data: doc.data(),
      }))
    );
  };

  useLayoutEffect(() => {
    fetchMessages();
  }, []);

  const sendMessage = async () => {
    Keyboard.dismiss();

    if (input !== "") {
      const docRef = doc(db, "chats", id);
      const colRef = collection(docRef, "messages");
      await addDoc(colRef, {
        message: input,
        timestamp: serverTimestamp(),
        displayName: authentication.currentUser.displayName,
        email: authentication.currentUser.email,
        photoURL: authentication.currentUser.photoURL,
      });
      fetchMessages();
    }
  };

  ...

A suggested solution is to subscribe to the collection with a snapshot listener. This will receive changes to the collection when the collection is updated, not just when this client sends a message.

Example:

import { addDoc, collection, query, orderBy, onSnapshot } from "firebase/firestore";

const ChatScreen = ({ navigation, route, ...props }) => {
  const { id, chatName } = route.params;
  const [input, setInput] = useState("");
  const [messages, setMessages] = useState([]);

  useLayoutEffect(() => {
    const unsubscribe = onSnapshot(
      query(
        collection(db, "chats", id, "messages"),
        orderBy("timestamp", "desc")
      ),
      (querySnapshot) => {
        const messages = [];
        querySnapshot.forEach((doc) => {
          cities.push({ id: doc.id, data: doc.data() });
        });
        setMessages(messages);
      }
    );

    return unsubscribe;
  }, []);

  const sendMessage = async () => {
    Keyboard.dismiss();

    if (input !== "") {
      const docRef = doc(db, "chats", id);
      const colRef = collection(docRef, "messages");
      addDoc(colRef, {
        message: input,
        timestamp: serverTimestamp(),
        displayName: authentication.currentUser.displayName,
        email: authentication.currentUser.email,
        photoURL: authentication.currentUser.photoURL,
      });
    }
  };

  ...
  • Related