useQuery - action_id에 해당하는 room id들 전부 가져와서 배열에 넣기(useState)
useEffect 안에서 map으로 room id들 map해서 전부 다 구독하기 + 채팅방 rooms_info 테이블도 같이 구독하기(새로운 채팅방 추가될때 바로 업데이트 되도록)
-> 구독할때 room id 가져오는 쿼리키 무효화, 채팅방 내용 가져오는 쿼리키 무효화
useQuery로 room id에 해당하는 닉네임, 아바타, 마지막 메시지, 마지막 메시지 시간 가져오기
-> 구독하고 insert했을때 실행되는 함수 부분에 '가져온 정보 무효화'하는 로직 넣어주기
가져온 정보들은 채팅방 jsx map으로 뿌려주기
// PrivateChatsList.tsx
const queryClient = useQueryClient();
// 채팅방 room_id 배열 가져오기
const { data: roomIds, error } = useQuery({
queryKey: [QUERY_KEY_PRIVATE_ROOM_IDS],
queryFn: async () => {
const response = await getPrivateRoomIds(action_id);
return response;
},
});
useEffect(() => {
// 채팅방 테이블 변경사항 구독 - 새 채팅방 insert될때 채팅방 리스트 실시간 업데이트
const chatRoomsSubscription = supabase.channel(`{${action_id}}`).on(
"postgres_changes",
{ event: "INSERT", schema: "public", table: "chat_rooms_info" },
(payload) => {
queryClient.invalidateQueries({
queryKey: [QUERY_KEY_PRIVATE_ROOM_IDS],
});
},
);
return () => {
chatRoomsSubscription.unsubscribe();
};
}, [action_id]);
useEffect(() => {
// 채팅내용 구독 - room_id 별로 채팅내용 변경사항 구독
const subscriptions = roomIds?.map((roomId) => {
const subscription = supabase
.channel(`${roomId}`)
.on(
"postgres_changes",
{ event: "INSERT", schema: "public", table: "chat_messages" },
(payload) => {
queryClient.invalidateQueries({
queryKey: [QUERY_KEY_PRIVATE_CHATS_LIST],
}),
// 채팅방 개설은 되어있지만, 메시지가 하나도 없었던 경우 대비
queryClient.invalidateQueries({
queryKey: [QUERY_KEY_PRIVATE_ROOM_IDS],
});
},
)
.subscribe();
return subscription;
});
return () => {
subscriptions?.map((subscription) => {
return subscription.unsubscribe();
});
};
}, [roomIds]);
// 채팅방 리스트 가져오기
const { data: privateChatsList, error: privateChatListError } = useQuery({
queryKey: [QUERY_KEY_PRIVATE_CHATS_LIST],
queryFn: async () => {
if (roomIds) {
return await getPrivateChatsList(roomIds);
}
return [];
},
enabled: !!roomIds,
});
if (error || privateChatListError) {
return <div>Error</div>;
}
// privateChat-api.ts
// 액션별 1:1 채팅방 room_id들 배열로 가져오기
export const getPrivateRoomIds = async (action_id: string) => {
const { data, error } = await supabase
.from("chat_rooms_info")
.select("id")
.eq("action_id", action_id)
.eq("room_type", "개인");
if (error) {
console.log("error", error.message);
throw error;
}
const roomIds = data.map((item) => {
return item.id;
});
return roomIds;
};
// 1:1 채팅방 리스트 가져오기 - 📝 수정 예정(채팅 참가자의 정보를 가져와야함)
export const getPrivateChatsList = async (roomIds: string[]) => {
const chatPromises = roomIds.map(async (roomId) => {
const { data, error } = await supabase
.from("chat_messages")
.select("created_at, content, room_id, users(display_name, profile_img)")
.eq("room_id", roomId)
.order("created_at", { ascending: false })
.limit(1);
if (error) {
console.log(
`Error fetching chat messages for room ${roomId}: ${error.message}`,
);
throw error;
}
if (data && data.length > 0) {
return data[0]; // 가장 최신 메시지 반환
} else {
// 메시지 없이 빈 채팅방인 경우
return;
}
});
const chatList = await Promise.all(chatPromises);
return chatList;
};
일...일단 성공...! (?) 왜 되지...? 다른건 왜 안됐지..? 😂
로직 복잡... 심지어 useQuery를 useEffect 위에서 썼는데 되고, 두번째 useQuery도 같이 useEffect위로 올리니까 에러가 났다.
roomIds를 가져오는 로직에서 몇시간을 애를 먹었다. 결국 되긴 됐는데... 아직 찜찜한 상황인 것 같다. 뭐 하나 잘못 건드리면 와르르 되는 상태랄까...흑
예를 들면, useQuery로 가져온 roomIds가 undefined일 수 있으니까 처리하려고 아래에 if문 넣었더니 바로 에러가 난다.
그래서 그냥 가만히 둬야함....(?)🤯 다양하게 해봤던 시도들
- 처음엔 roomIds를 useState로 정해놓고, room_id들 배열 가져와서 set해주는 fetchData 비동기 함수를 useEffect 안에서 실행했다가, 무한대로 계속 roomIds를 업데이트해서 실패
- fetchData를 useEffect 밖에다 두고 useEffect에서는 실행만 해보기
- room_id들 가져와서 set하는 로직만 따로 useEffect 분리해보기
(근데 이렇게 하면 새로운 채팅방이 insert됐을때 roomIds state가 저절로 업데이트되지 않기 때문에 옳은 방법이 아니었음)- useQuery로 room_id들 가져와보기
(이후로 이리저리 useQuery를 이리저리 위치도 이동해보고, 별의 별 짓을 다했다.)