Skip to content

Commit cbee99a

Browse files
authored
Merge pull request #102 from six-goguma/Fix/issue-#98
페이지 언마운트 시 웹소켓 연결 해제
2 parents bf4ae4d + b20c2c3 commit cbee99a

File tree

6 files changed

+191
-212
lines changed

6 files changed

+191
-212
lines changed

src/pages/chat/apis/chat-ws.api.ts

Lines changed: 0 additions & 26 deletions
This file was deleted.

src/pages/chat/apis/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
export * from './chat-rooms.api';
22
export * from './chat-rooms.type';
3-
export * from './chat-ws.api';

src/pages/chat/ui/ChatPage.tsx

Lines changed: 65 additions & 130 deletions
Original file line numberDiff line numberDiff line change
@@ -5,46 +5,52 @@ import { Flex, Button, Text, useDisclosure } from '@chakra-ui/react';
55

66
import { RouterPath } from '@shared/constants';
77
import { useCustomToast } from '@shared/hooks';
8-
import { BASE_URI, BASE_WS_URI } from '@shared/service';
8+
import { BASE_URI } from '@shared/service';
9+
import {
10+
connectWebSocket,
11+
disconnectWebSocket,
12+
subsribeToNoRoom,
13+
subscribeToRoom,
14+
unsubscribeFromRoom,
15+
sendMessage as sendMessageViaWebSocket,
16+
subscribeToAllUsers,
17+
subscribeToRoomUsers,
18+
} from '@shared/service';
919
import { authStorage } from '@shared/utils';
1020

1121
import { ChatRoomList, ChatRoomInside, ChatUserList } from '../components';
1222
import { useGetChatRooms, useCreateChatRoom } from '../hooks';
13-
import { Client } from '@stomp/stompjs';
1423

1524
export const ChatPage = () => {
25+
const [page, setPage] = useState(0);
26+
const size = 10;
27+
const sort = 'createdAt,desc';
28+
const { data: chatRooms, refetch } = useGetChatRooms(page, size, sort);
29+
1630
const [roomName, setRoomName] = useState('');
1731
const [newRoomName, setNewRoomName] = useState('');
1832
const [messages, setMessages] = useState<{ sender: string; content: string; email: string }[]>(
1933
[],
20-
); // 메세지 <- 총 메세지(rest + 소켓)
34+
);
2135
const [socketMessages, setSocketMessages] = useState<
2236
{ sender: string; content: string; email: string }[]
2337
>([]);
2438
const [newMessage, setNewMessage] = useState('');
25-
const [stompClient, setStompClient] = useState<Client | null>(null);
26-
27-
const [page, setPage] = useState(0);
28-
const size = 10;
29-
const sort = 'createdAt,desc';
30-
const { data: chatRooms, refetch } = useGetChatRooms(page, size, sort);
31-
32-
const [usersInRooms, setUsersInRooms] = useState<{ userName: string; roomName: string }[]>([]); // 채팅방 사용자 목록
33-
const [roomUserList, setRoomUserList] = useState<{ [key: string]: number }>({}); // 각 방의 접속자 목록
34-
const [isComposing, setIsComposing] = useState(false); // IME 입력 상태 관리
35-
36-
const messagesEndRef = useRef<HTMLDivElement>(null); // 채팅 메시지 스크롤 조작을 위한 Ref
37-
const messageListRef = useRef<HTMLDivElement>(null); // 메시지 목록 스크롤 조작을 위한 Ref
39+
const [usersInRooms, setUsersInRooms] = useState<{ userName: string; roomName: string }[]>([]);
40+
const [roomUserList, setRoomUserList] = useState<{ [key: string]: number }>({});
41+
const [isComposing, setIsComposing] = useState(false);
42+
const messagesEndRef = useRef<HTMLDivElement>(null);
43+
const messageListRef = useRef<HTMLDivElement>(null);
3844
const navigate = useNavigate();
3945
const { isOpen, onOpen, onClose } = useDisclosure();
4046

4147
const { mutate: createRoom } = useCreateChatRoom();
42-
const customToast = useCustomToast();
4348

49+
const customToast = useCustomToast();
4450
const [messagePage, setMessagePage] = useState(0);
4551
const [hasMoreMessages, setHasMoreMessages] = useState(true);
46-
4752
const [userName, setUserName] = useState(authStorage.nickName.get());
53+
4854
const [email, setEmail] = useState(authStorage.email.get());
4955

5056
useEffect(() => {
@@ -99,11 +105,8 @@ export const ChatPage = () => {
99105
if (roomName && messagePage > 0) {
100106
fetchRecentMessages(roomName, messagePage);
101107
}
108+
}, [messagePage, roomName]);
102109

103-
// eslint-disable-next-line react-hooks/exhaustive-deps
104-
}, [messagePage]);
105-
106-
//새 메세지 추가 시 자동 스크롤
107110
useEffect(() => {
108111
if (messagesEndRef.current) {
109112
messagesEndRef.current.scrollIntoView({ behavior: 'smooth' });
@@ -124,127 +127,64 @@ export const ChatPage = () => {
124127
setTimeout(() => refetch(), 500);
125128
};
126129

127-
useEffect(() => {
128-
connectToWebSocket();
129-
// eslint-disable-next-line react-hooks/exhaustive-deps
130-
}, []);
131-
132-
const connectToWebSocket = () => {
133-
if (stompClient) {
134-
stompClient.deactivate();
135-
}
136-
137-
const client = new Client({
138-
brokerURL: `${BASE_WS_URI}/api/ws`,
139-
debug: (str) => console.log(str),
140-
onConnect: () => {
141-
console.log('WebSocket에 연결되었습니다.');
142-
143-
client.subscribe('/topic/users', (messageOutput) => {
144-
const userList = JSON.parse(messageOutput.body);
145-
setUsersInRooms(userList);
146-
});
147-
148-
client.subscribe('/topic/room-users', (messageOutput) => {
149-
const roomUserList = JSON.parse(messageOutput.body);
150-
setRoomUserList(roomUserList);
151-
});
130+
const handleSendMessage = () => {
131+
if (!newMessage.trim()) return;
152132

153-
client.publish({
154-
destination: '/api/app/chat/join',
155-
body: JSON.stringify({
156-
userName: userName,
157-
roomName: '채팅방 미접속',
158-
}),
159-
});
160-
},
161-
onStompError: (frame) => {
162-
console.error(`STOMP 오류: ${frame}`);
163-
},
164-
});
133+
const messageRequest = {
134+
sender: userName,
135+
email,
136+
content: newMessage,
137+
roomName,
138+
};
165139

166-
client.activate();
167-
setStompClient(client);
140+
sendMessageViaWebSocket(roomName, messageRequest);
141+
setNewMessage('');
168142
};
169143

170-
const connectToChatRoom = () => {
171-
if (!roomName || !userName) return;
172-
173-
if (stompClient) {
174-
stompClient.deactivate();
175-
}
176-
177-
const client = new Client({
178-
brokerURL: `${BASE_WS_URI}/api/ws`,
179-
debug: (str) => console.log(str),
180-
onConnect: () => {
181-
console.log(`${roomName} 채팅방에 연결되었습니다.`);
182-
183-
client.subscribe(`/topic/${roomName}`, (messageOutput) => {
184-
const message = JSON.parse(messageOutput.body);
185-
186-
message.content = message.content + ' ';
187-
188-
setSocketMessages((prevMessages) => [message, ...prevMessages]);
189-
setMessages((prevMessages) => [message, ...prevMessages]);
190-
});
191-
192-
client.subscribe('/topic/users', (messageOutput) => {
193-
const userList = JSON.parse(messageOutput.body);
194-
setUsersInRooms(userList);
195-
});
196-
197-
client.subscribe('/topic/room-users', (messageOutput) => {
198-
const roomUserList = JSON.parse(messageOutput.body);
199-
setRoomUserList(roomUserList);
200-
});
144+
useEffect(() => {
145+
connectWebSocket(() => {
146+
subsribeToNoRoom();
147+
subscribeToAllUsers((userList) => {
148+
setUsersInRooms(userList);
149+
});
201150

202-
client.publish({
203-
destination: '/api/app/chat/join',
204-
body: JSON.stringify({ userName: userName, roomName }),
205-
});
206-
},
207-
onStompError: (frame) => {
208-
console.error(`STOMP 오류: ${frame}`);
209-
},
151+
subscribeToRoomUsers((roomUserList) => {
152+
setRoomUserList(roomUserList);
153+
});
210154
});
211155

212-
client.activate();
213-
setStompClient(client);
214-
};
156+
return () => {
157+
disconnectWebSocket();
158+
};
159+
}, []);
215160

216161
useEffect(() => {
217162
if (roomName) {
218163
setMessagePage(0);
219164
setMessages([]);
220165
fetchRecentMessages(roomName, 0);
221-
connectToChatRoom();
222-
}
223-
// eslint-disable-next-line react-hooks/exhaustive-deps
224-
}, [roomName]);
225-
226-
const handleSendMessage = () => {
227-
if (!stompClient || !stompClient.connected) {
228-
console.log('WebSocket 연결이 활성화되지 않았습니다.');
229-
return;
230-
}
166+
disconnectWebSocket();
167+
connectWebSocket(() => {
168+
subscribeToAllUsers((userList) => {
169+
setUsersInRooms(userList);
170+
});
231171

232-
if (newMessage.trim()) {
233-
const messageRequest = {
234-
sender: userName,
235-
email,
236-
content: newMessage,
237-
roomName,
238-
};
172+
subscribeToRoomUsers((roomUserList) => {
173+
setRoomUserList(roomUserList);
174+
});
239175

240-
stompClient.publish({
241-
destination: `/api/app/chat/${roomName}`,
242-
body: JSON.stringify(messageRequest),
176+
subscribeToRoom(roomName, (message) => {
177+
setSocketMessages((prevMessages) => [message, ...prevMessages]);
178+
setMessages((prevMessages) => [message, ...prevMessages]);
179+
});
243180
});
244181

245-
setNewMessage('');
182+
return () => {
183+
unsubscribeFromRoom(roomName);
184+
disconnectWebSocket();
185+
};
246186
}
247-
};
187+
}, [roomName]);
248188

249189
return (
250190
<Flex flexDir='column' alignItems='center' w='full' h='full'>
@@ -263,7 +203,6 @@ export const ChatPage = () => {
263203
<Text display={{ base: 'block', sm: 'none' }} mt='10px' fontSize='sm' color='gray.600'>
264204
밑으로 스크롤하면 채팅과 현재 접속자 목록을 볼 수 있어요
265205
</Text>
266-
{/* 채팅방 목록 */}
267206
<ChatRoomList
268207
chatRooms={chatRooms}
269208
roomName={roomName}
@@ -280,8 +219,6 @@ export const ChatPage = () => {
280219
isOpen={isOpen}
281220
onClose={onClose}
282221
/>
283-
284-
{/* 채팅방 */}
285222
<ChatRoomInside
286223
messages={messages}
287224
newMessage={newMessage}
@@ -297,8 +234,6 @@ export const ChatPage = () => {
297234
setIsComposing={setIsComposing}
298235
handleMessageListScroll={handleMessageListScroll}
299236
/>
300-
301-
{/* 현재 채팅방 사용자 목록 */}
302237
<ChatUserList usersInRooms={usersInRooms} />
303238
</Flex>
304239
</Flex>

src/shared/service/config/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
export * from './instance';
2-
export * from './wsclient';
2+
export * from './wsinstance';

src/shared/service/config/wsclient.ts

Lines changed: 0 additions & 54 deletions
This file was deleted.

0 commit comments

Comments
 (0)