@@ -5,46 +5,52 @@ import { Flex, Button, Text, useDisclosure } from '@chakra-ui/react';
55
66import { RouterPath } from '@shared/constants' ;
77import { 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' ;
919import { authStorage } from '@shared/utils' ;
1020
1121import { ChatRoomList , ChatRoomInside , ChatUserList } from '../components' ;
1222import { useGetChatRooms , useCreateChatRoom } from '../hooks' ;
13- import { Client } from '@stomp/stompjs' ;
1423
1524export 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 >
0 commit comments