Skip to content

Commit

Permalink
πŸ› μ±„νŒ… νŽ˜μ΄μ§€ 슀크둀 및 데이터 버그 μˆ˜μ • (#255)
Browse files Browse the repository at this point in the history
  • Loading branch information
rwaeng committed Jan 21, 2025
1 parent d1cc8df commit 4f2ced4
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 85 deletions.
6 changes: 3 additions & 3 deletions src/components/chatting/ChatBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import { ReactComponent as Send } from '@src/assets/icons/ck_arrow_up.svg';
import { ReactComponent as SendGreen } from '@src/assets/icons/ck_arrow_right.svg';
import { sendHandler } from '@src/apis/chat';
import useLoaderData from '@src/hooks/useRoaderData';
import { useRoomInfo } from '@src/hooks/query/useDm';
import { usePostMessageRoom } from '@src/hooks/query/chat';
import type { MessageReq } from '@src/types/apis/chat';

const ChatBar = ({ nickname }: { nickname: string }) => {
const { id: memberId } = useLoaderData<{ id: number }>();
const { roomInfo } = useRoomInfo(memberId);
const { roomInfo } = usePostMessageRoom(memberId);
const [chat, setChat] = useState<string>('');

const handleChangeInput = (e: React.ChangeEvent<HTMLInputElement>) => {
Expand Down Expand Up @@ -61,7 +61,7 @@ export default ChatBar;
const SLayout = styled.div`
display: flex;
gap: 0.625rem;
position: sticky;
position: fixed;
bottom: 0;
width: 100%;
Expand Down
133 changes: 51 additions & 82 deletions src/pages/chatting/ChattingPage.tsx
Original file line number Diff line number Diff line change
@@ -1,52 +1,53 @@
import styled from 'styled-components';
import React, { useEffect, useRef, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { useInView } from 'react-intersection-observer';
import { connectHandler, disconnectHandler } from '@src/apis/chat';
import type { DM } from '@src/types/messageRoom';
import type { ChatEventRes } from '@src/types/apis/chat';
import useLoaderData from '@src/hooks/useRoaderData';
import { useMessage, useRoomInfo } from '@src/hooks/query/useDm';
import { useGetDMList, usePostMessageRoom } from '@src/hooks/query/chat';
import ChatBar from '@src/components/chatting/ChatBar';
import ChatItem from '@src/components/chatting/ChatItem';
import DateLine from '@src/components/common/DateLine';
import Header from '@src/components/common/Header';
import LoadingPage from '@src/components/common/LoadingPage';

const ChattingPage = () => {
const { id: memberId } = useLoaderData<{ id: number }>();
const { roomInfo } = useRoomInfo(memberId);
const [roomId, setRoomId] = useState<number>();
const {
messages: data,
isLoading,
fetchNextPage,
isFetchingNextPage,
hasNextPage,
} = useMessage(roomId ?? -1);
const { roomInfo } = usePostMessageRoom(memberId);
const { data, fetchNextPage, hasNextPage, refetch } = useGetDMList(
roomInfo?.messageRoomId ?? 0,
);
const [messages, setMessages] = useState<DM[]>([]);
const [prevHeight, setPrevHeight] = useState<number>(-1);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const targetRef = useRef<any>(null);
const [newMessages, setNewMessages] = useState<DM[]>([]);
const [isInitial, setIsInitial] = useState<boolean>(true);
const { ref: targetRef, inView } = useInView();
const chatRef = useRef<HTMLDivElement>(null);

// 데이터 fetching
const navigate = useNavigate();

const handleRefresh = async () => {
refetch();
navigate(-1);
};

// 데이터 패칭
useEffect(() => {
if (data) {
const uniqueMessages = data.filter(
(newMessage) => !messages.some((msg) => msg.id === newMessage.id),
);

// κΈ°μ‘΄ λ©”μ‹œμ§€μ— μƒˆλ‘œμš΄ λ©”μ‹œμ§€λ§Œ μΆ”κ°€
if (uniqueMessages.length > 0) {
setMessages((prevMessages) => [...prevMessages, ...uniqueMessages]);
}
}
}, [data]);
if (!inView) return;

if (hasNextPage) fetchNextPage();
if (data) setMessages(data);
}, [inView, hasNextPage]);

// 졜초 슀크둀 ν•˜λ‹¨ 이동
useEffect(() => {
if (roomInfo && roomInfo.messageRoomId !== roomId) {
setRoomId(roomInfo.messageRoomId);
if (chatRef.current && messages.length > 0) {
if (isInitial) {
chatRef.current.scrollTop = chatRef.current.scrollHeight;
setIsInitial(false);
}
}
}, [roomInfo]);
}, [messages]);

useEffect(() => {
// λ©”μ‹œμ§€ ν•Έλ“€λŸ¬ μ •μ˜ (μƒˆλ‘œμš΄ λ©”μ‹œμ§€κ°€ 도착할 λ•Œ 호좜)
Expand All @@ -62,22 +63,14 @@ const ChattingPage = () => {
) {
const newMessage: DM = {
id: message.payload.id,
messageRoomId: message.payload.messageRoomId || 0,
messageRoomId: message.payload.messageRoomId,
memberId: message.payload.memberId,
content: message.payload.content ?? '',
content: message.payload.content,
createdAt: message.payload.createdAt,
// reactions: {},
};
setMessages((prevMessages) => {
if (prevMessages.some((msg) => msg.id === newMessage.id)) {
return prevMessages;
}
return [newMessage, ...prevMessages];
});

if (chatRef.current) {
chatRef.current.scrollTop = chatRef.current.scrollHeight;
}

setNewMessages((prev) => [newMessage, ...prev]);
}
};

Expand All @@ -88,51 +81,25 @@ const ChattingPage = () => {
// μ»΄ν¬λ„ŒνŠΈ μ–Έλ§ˆμš΄νŠΈ μ‹œ WebSocket μ—°κ²° ν•΄μ œ
disconnectHandler();
};
}, [roomInfo]);

// μ˜΅μ €λ²„
useEffect(() => {
const observer = new IntersectionObserver(
(entries) => {
const target = entries[0];
if (target.isIntersecting && hasNextPage && !isFetchingNextPage) {
setPrevHeight(chatRef.current?.scrollHeight || prevHeight);
fetchNextPage();
}
},
{
root: null,
rootMargin: '0px',
threshold: 1.0,
},
);

const targetElement = targetRef.current;
if (targetElement) observer.observe(targetElement);

return () => {
if (targetElement) observer.unobserve(targetElement);
};
}, [fetchNextPage, hasNextPage, isFetchingNextPage, targetRef]);
}, [roomInfo, messages]);

// μƒˆλ‘œμš΄ λ©”μ‹œμ§€ λ³΄λƒˆμ„ λ•Œ 슀크둀 이동
useEffect(() => {
// 처음 μ±„νŒ…λ°© μ ‘μ†μ‹œ 슀크둀 ν•˜λ‹¨ 이동
if (prevHeight === -1 && chatRef.current) {
if (chatRef.current) {
chatRef.current.scrollTop = chatRef.current.scrollHeight;
}
}, [messages]);

if (!data || isLoading) {
return <LoadingPage />;
}
}, [newMessages]);

return (
<>
<Header text={roomInfo?.title ?? ''} headerType='back' />
<SLayout ref={chatRef}>
<div ref={targetRef} />
<Header
text={roomInfo?.title ?? ''}
headerType='back'
onClick={handleRefresh}
/>
<Layout ref={chatRef}>
<Container>
{messages.map((it, idx) => {
{[...newMessages, ...messages].map((it, idx) => {
const participant = roomInfo?.participants?.[String(it.memberId)];
const imgUrl = participant?.profileImg || undefined;
const nickname = participant?.nickname || '';
Expand Down Expand Up @@ -164,23 +131,25 @@ const ChattingPage = () => {
</React.Fragment>
);
})}
<div ref={targetRef} />
</Container>
</SLayout>
</Layout>
<ChatBar nickname={roomInfo?.title ?? ''} />
</>
);
};

export default ChattingPage;

const SLayout = styled.div`
const Layout = styled.div`
display: flex;
position: relative;
flex-direction: column;
padding-top: 70px;
padding-top: 4.375rem;
padding-bottom: 4.4375rem;
width: 100%;
height: calc(100% - 70px);
height: 100%;
overflow: auto;
`;
Expand Down

0 comments on commit 4f2ced4

Please sign in to comment.