Search code examples
reactjsfirebasegoogle-cloud-firestore

component is re-rendering after receiving new data from server


I'm trying update my chats list. I'm receiving an object from server using "onSnapshot" query method of firestore and these object represents users, groups and channels. Then I'm combining these object using Object.assign method and then turning them into array so I can use map. The problem is when other users deletes me from their group, that group is not vanished in chats list.

Receiving groups data from server

{
group1: {...},
group2: {...},
}

Receiving groups data from server after deletion

{
group1: {...},
}
export default function List(){

  const [chats, setChats] = useState([]);
  const [groups, setGroups] = useState([]);
  const [channels, setChannels] = useState([]);
  const currentUser = auth.currentUser;

useEffect(() => {
      const getChats = () => {
        const fetchUsers = onSnapshot(
          doc(db, "userChats", currentUser.uid),
          (doc) => {
            if (doc.data()) {
              setChats(doc.data());
            }else{
              setChats([])
              
            }
          }
        );

        const fetchGroups = onSnapshot(
          doc(db, "userGroups", currentUser.uid),
          (doc) => {
            if (doc.data()) {
              setGroups(doc.data());
            }else{
              setGroups([])
              }
          }
        );

        const fetchChannels = onSnapshot(
          doc(db, "userChannels", currentUser.uid),
          (doc) => {
            if (doc.data()) {
              setChannels(doc.data());
            }else{
              setChannels([])
            }
          }
        );
        return () => {
          fetchUsers();
          fetchGroups();
          fetchChannels();
        };
      };
      currentUser.uid && getChats();
  }, [currentUser.uid]);

 return (
      <div className="List">
        {Object.entries(Object.assign(chats, groups, channels))
          ?.sort((a, b) => b[1].date - a[1].date)
          ?.map((chat) => (
          <Chats
              chatVal={chat}
              key={chat[0]}
            />
          ))}
      </div>
    )
}

Solution

  • use spread operator instead of using Object.assign. Object.assign mutates the first object passed to it, which can lead to stale data if an object is removed and then not properly updated.

    try below code, i have made the required changes and i think it should work.

    import React, { useEffect, useState } from 'react';
    import { onSnapshot, doc } from 'firebase/firestore';
    import { auth, db } from './firebase'; // Adjust the path as necessary
    import Chats from './Chats'; // Adjust the path as necessary
    
    export default function List() {
      const [chats, setChats] = useState([]);
      const [groups, setGroups] = useState([]);
      const [channels, setChannels] = useState([]);
      const currentUser = auth.currentUser;
    
      useEffect(() => {
        if (!currentUser?.uid) return;
    
        const fetchUsers = onSnapshot(
          doc(db, "userChats", currentUser.uid),
          (doc) => {
            setChats(doc.data() || []);
          }
        );
    
        const fetchGroups = onSnapshot(
          doc(db, "userGroups", currentUser.uid),
          (doc) => {
            setGroups(doc.data() || []);
          }
        );
    
        const fetchChannels = onSnapshot(
          doc(db, "userChannels", currentUser.uid),
          (doc) => {
            setChannels(doc.data() || []);
          }
        );
    
        return () => {
          fetchUsers();
          fetchGroups();
          fetchChannels();
        };
      }, [currentUser?.uid]);
    
      const combinedChats = Object.entries({
        ...chats,
        ...groups,
        ...channels
      });
    
      return (
        <div className="List">
          {combinedChats
            ?.sort((a, b) => b[1].date - a[1].date)
            ?.map((chat) => (
              <Chats
                chatVal={chat}
                key={chat[0]}
              />
            ))}
        </div>
      );
    }
    

    let me know!