Reputation: 31
I am trying to attatch a listener to the chatRoomIds subcollection for a specific user from the User collection.After retriving the chatroomIds for the specific users I have to loop through each to get the specific chatRoom document from the chatRoomIds array in which each element is an object containing chatRoomId that will be used to query for the specific chatRoom.The problem is that the state is working correctly but does not render the Messaage Card component unless I toggle another state in the Message component in the react dev tools on the messages link again after everything loads.
function Message() {
const [currentUser] = useAuthState(auth)
const [{user}] = useStateValue()
const {show, setNotificationPopup, setShow} = useChat();
const [chats, setChats] = useState([])
const [loading, setLoading] = useState(true)
const [chatRoomArraySnap, error] = useCollection(db.collection("Users").doc(user?.uid).collection('ChatRoomIds'))
const chatList = []
const {setLoader, loader} = useLoader();
let chatRoomIds = []
let params = useParams();
const messageId = params.id;
const userObj = {
email: user?.email,
objId: user?.uid,
userName: user?.displayName
};
useEffect(() => {
{
params.id ? setShow(true)
:
setShow(false)
}
}, [])
useEffect(() =>{
// chatList = []
if(user.uid){
db.collection("Users").doc(user.uid).collection('ChatRoomIds').get()
.then(
snapshot => {
snapshot.docs.map((each) => {
// chatRoomIds.push(each.data())
db.collection('ChatRooms').where("chatRoomId", "==", each.data().id).orderBy('dateLastUpdated','desc').onSnapshot(snapshot => {
snapshot.docs.forEach(doc => {
chats.push(doc.data())
console.log(doc.data())
})
// setChats(chatList)
setLoading(false)
// snapshot.docChanges().forEach((change) => {
// if (change.type === "added") {
// console.log("New : ", change.doc.data());
// chatList.push(change.doc.data())
//
// }
// if (change.type === "modified") {
// console.log("Modified : ", change.doc.data());
// setNotificationPopup(change.doc.data())
//
// }
// if (change.type === "removed") {
// console.log("Removed : ", change.doc.data());
// }
// })
})
})
console.log(chatRoomIds)
// chatRoomIds?.map((each) => {
// db.collection('ChatRooms').where("chatRoomId", "==", each.id).orderBy('dateLastUpdated','desc').onSnapshot(snapshot => {
// snapshot.docs.forEach(doc => {
// chatList.push(doc.data())
// console.log(doc.data())
// })
//
// setChats(chatList)
// setLoading(false)
//
//
//
//
//
// // snapshot.docChanges().forEach((change) => {
// // if (change.type === "added") {
// // console.log("New : ", change.doc.data());
// // chatList.push(change.doc.data())
// //
// // }
// // if (change.type === "modified") {
// // console.log("Modified : ", change.doc.data());
// // setNotificationPopup(change.doc.data())
// //
// // }
// // if (change.type === "removed") {
// // console.log("Removed : ", change.doc.data());
// // }
// // })
//
//
// })
// })
}
)
console.log(chatList)
// if (chatRoomArraySnap) {
//
// chatRoomArraySnap.docs.map((each) => {
// chatRoomIds.push(each.data())
// })
// // chatList=[]
// // setChats([])
//
// chatRoomIds.map((each) => {
// db.collection('ChatRooms').where("chatRoomId", "==", each.id).orderBy('dateLastUpdated','desc').onSnapshot(snapshot => {
// snapshot.docs.forEach(doc => {
// chatList.push(doc.data())
// })
//
//
//
//
//
//
// // snapshot.docChanges().forEach((change) => {
// // if (change.type === "added") {
// // console.log("New : ", change.doc.data());
// // chatList.push(change.doc.data())
// //
// // }
// // if (change.type === "modified") {
// // console.log("Modified : ", change.doc.data());
// // setNotificationPopup(change.doc.data())
// //
// // }
// // if (change.type === "removed") {
// // console.log("Removed : ", change.doc.data());
// // }
// // })
//
//
// })
// })
// setChats(chatList)
// console.log(chatList)
//
// }
}
},[])
return (
<>
<Header/>
<div className='container'>
<div className='message '>
<div className='row'>
<div className='col-md-4 col-lg-4 col-sm-12 lg-view'>
<div className=' pt-3 user-list-section'>
<div className='lg-view'>
<h5 className='text-light ml-5 mb-5`'>Messages</h5>
<div className={`d-flex align-items-center`}>
<Search functionHandler={handleSearchChat} props={'#13161A'}/>
<CreateGroupBtn/>
</div>
</div>
<div className='user-list'>
{!loading && chats ? chats.map(chat => {
// console.log(chat.data());
return (<>
<MessageCard key={chat.chatRoomId}
id={chat.chatRoomId} chats={chat}/>
</>
)
}) : <></>}
</div>
</div>
</div>
{
!show ? <>
<div className='sm-view w-100 pl-3 pr-3 '>
<div className=' w-100 d-flex justify-content-center pt-4'>
<div className='flex-grow-1'>
<h4 className='text-light'>Messages</h4>
<p>Talk with your friends</p>
</div>
<div className="search-container flex-grow-1 ">
<div className='search d-flex float-right'>
<CreateGroupBtn/>
</div>
</div>
</div>
<Search functionHandler={handleSearchChat}/>
</div>
<div className='col-md-4 col-lg-4 col-sm-12 sm-view'>
<div className=' pt-3 user-list-section'>
<div className='lg-view'>
<h5 className='text-light ml-5 mb-5`'>Messages</h5>
<div className={`d-flex align-items-center`}>
<Search functionHandler={handleSearchChat} props={'#13161A'}/>
<CreateGroupBtn/>
</div>
</div>
<div className='user-list'>
{!loading && chats !== undefined && chats !== null && chats ? chats.map(chat => {
// console.log(chat.data());
return (<>
<MessageCard key={chat.chatRoomId}
id={chat.chatRoomId} chats={chat}/>
</>
)
}) : <></>}
</div>
</div>
</div>
</>
:
<>
<div className='col-md-8 p-0 col-lg-8 col-sm-12'>
{
messageId && currentUser.email && <MessageWindow/>
}
</div>
</>
}
</div>
</div>
</div>
{!show && <MobileNavbar/>}
</>
);
}
///Working Code
function Message() {
const [currentUser] = useAuthState(auth)
const [{user}] = useStateValue()
const {show, setShow} = useChat();
const [chats, setChats] = useState([])
const [loading, setLoading] = useState(true)
let params = useParams();
const messageId = params.id;
useEffect(() => {
{
params.id ? setShow(true)
:
setShow(false)
}
}, [])
useEffect(() => {
if (user.uid) {
db.collection("Users")
.doc(user.uid)
.collection("ChatRoomIds")
.get()
.then((snapshot) => {
snapshot.docs.map((each) => {
db.collection("ChatRooms")
.where("chatRoomId", "==", each.data().id)
.orderBy("dateLastUpdated", "desc")
.onSnapshot((snapshot) => {
console.log(snapshot.docs.map((doc) => doc.data()))
setChats((chats) =>
chats.concat(snapshot.docs.map((doc) => doc.data()))
);
setLoading(false)
});
});
});
}
}, []);
return (
<>
<Header/>
<div className='container'>
<div className='message '>
<div className='row'>
<div className='col-md-4 col-lg-4 col-sm-12 lg-view'>
<div className=' pt-3 user-list-section'>
<div className='lg-view'>
<h5 className='text-light ml-5 mb-5`'>Messages</h5>
<div className={`d-flex align-items-center`}>
<Search functionHandler={handleSearchChat} props={'#13161A'}/>
<CreateGroupBtn/>
</div>
</div>
<div className='user-list'>
{/*{!loading && chats ? chats.map(chat => {*/}
{/* // console.log(chat.data());*/}
{/* return (<>*/}
{/* <MessageCard key={chat.chatRoomId}*/}
{/* id={chat.chatRoomId} chats={chat}/>*/}
{/* </>*/}
{/* )*/}
{/*}) : <></>}*/}
</div>
</div>
</div>
{
!show ? <>
<div className='sm-view w-100 pl-3 pr-3 '>
<div className=' w-100 d-flex justify-content-center pt-4'>
<div className='flex-grow-1'>
<h4 className='text-light'>Messages</h4>
<p>Talk with your friends</p>
</div>
<div className="search-container flex-grow-1 ">
<div className='search d-flex float-right'>
<CreateGroupBtn/>
</div>
</div>
</div>
<Search functionHandler={handleSearchChat}/>
</div>
<div className='col-md-4 col-lg-4 col-sm-12 sm-view'>
<div className=' pt-3 user-list-section'>
<div className='lg-view'>
<h5 className='text-light ml-5 mb-5`'>Messages</h5>
<div className={`d-flex align-items-center`}>
<Search functionHandler={handleSearchChat} props={'#13161A'}/>
<CreateGroupBtn/>
</div>
</div>
<div className='user-list'>
{!loading && chats ? chats.map(chat => {
return (<>
<MessageCard key={chat.chatRoomId}
id={chat.chatRoomId} chats={chat}/>
</>
)
}) : <></>}
</div>
</div>
</div>
</>
:
<>
<div className='col-md-8 p-0 col-lg-8 col-sm-12'>
{
messageId && currentUser.email && <MessageWindow/>
}
</div>
</>
}
</div>
</div>
</div>
{!show && <MobileNavbar/>}
</>
);
}
export default Message;
Upvotes: 1
Views: 253
Reputation: 202618
You've a lot of commented out code, but what isn't commented out has a glaring issue, state mutation. You are pushing directly into the chats
state array. This is why you have to toggle/update some other state in order to trigger the component to rerender and expose the mutation.
You should properly enqueue these chat
updates. On the last/innermost snapshot you should use a functional state update to update from the previous state and because you are working in a loop, and concatenate an array of new chat documents.
The
concat()
method is used to merge two or more arrays. This method does not change the existing arrays, but instead returns a new array.
The
map()
method creates a new array populated with the results of calling a provided function on every element in the calling array.
.onSnapshot((snapshot) => {
setChats((chats) =>
chats.concat(snapshot.docs.map((doc) => doc.data()))
);
});
Example:
useEffect(() => {
if (user.uid) {
db.collection("Users")
.doc(user.uid)
.collection("ChatRoomIds")
.get()
.then((snapshot) => {
snapshot.docs.map((each) => {
db.collection("ChatRooms")
.where("chatRoomId", "==", each.data().id)
.orderBy("dateLastUpdated", "desc")
.onSnapshot((snapshot) => {
setChats((chats) =>
chats.concat(snapshot.docs.map((doc) => doc.data()))
);
});
});
});
}
}, []);
Still use a functional state update but run the chats
array through a filter first to check if there are no new chats with matching chatRoomId
properties. If there is a match return false to remove it from the array, otherwise keep it. The filter function returns a new array that you can concatenate to the new chats results.
useEffect(() => {
if (user.uid) {
db.collection("Users")
.doc(user.uid)
.collection("ChatRoomIds")
.get()
.then((snapshot) => {
snapshot.docs.map((each) => {
db.collection("ChatRooms")
.where("chatRoomId", "==", each.data().id)
.orderBy("dateLastUpdated", "desc")
.onSnapshot((snapshot) => {
const newChats = snapshot.docs.map((doc) => doc.data());
setChats((chats) => {
const filtered = chats.filter(chat =>
!newChats.some(newChat =>
newChat.chatRoomId === chat.chatRoomId
)
);
newChats.concat(filtered);
});
});
});
});
}
}, []);
Upvotes: 2