@@ -57,6 +57,9 @@ const GameLayout = () => {
5757
5858 const { isLoading, data } = useApiQuery ( [ 'authme' ] , ( ) => authMeRequest ( ) ) ;
5959
60+ const missedHeartbeatCount = useRef ( 0 ) ;
61+ const heartbeatCheckTimer = useRef ( null ) ;
62+
6063 useEffect ( ( ) => {
6164 if ( data ) {
6265 setLoginUser ( data ) ;
@@ -66,6 +69,9 @@ const GameLayout = () => {
6669 const disconnectRef = useRef ( null ) ;
6770 const ignorePopState = useRef ( false ) ;
6871
72+
73+
74+
6975 const handleStompMessage = useCallback (
7076 ( payload ) => {
7177 console . log ( 'receive message: ' , payload ) ;
@@ -120,8 +126,15 @@ const GameLayout = () => {
120126 if ( disconnectRef . current ) {
121127 disconnectRef . current ( ) ;
122128 }
129+ localStorage . removeItem ( `enteredRoom_${ roomId } ` ) ;
123130 navigate ( '/room' ) ;
124131 break ;
132+ case 'HEARTBEAT' :
133+ if ( sendMessageRef . current ) {
134+ sendMessageRef . current ( `/pub/heartbeat/pong` , '' ) ;
135+ }
136+ missedHeartbeatCount . current = 0 ;
137+ break ;
125138 default :
126139 console . warn ( '알 수 없는 메시지' , payload ) ;
127140 }
@@ -141,11 +154,39 @@ const GameLayout = () => {
141154 ] ,
142155 ) ;
143156
157+
144158 const { sendMessage, disconnect } = useStompClient (
145- roomId ,
146- handleStompMessage ,
159+ roomId ,
160+ handleStompMessage ,
147161 ) ;
148162
163+ const sendMessageRef = useRef ( null ) ;
164+
165+ useEffect ( ( ) => {
166+ heartbeatCheckTimer . current = setInterval ( ( ) => {
167+ missedHeartbeatCount . current += 1 ;
168+
169+ if ( missedHeartbeatCount . current >= 3 ) {
170+ if ( disconnectRef . current ) {
171+ disconnectRef . current ( ) ; // stompClient.deactivate()
172+ localStorage . removeItem ( `enteredRoom_${ roomId } ` ) ;
173+ navigate ( '/room' ) ;
174+ }
175+
176+ clearInterval ( heartbeatCheckTimer . current ) ; // 더 이상 체크 안 해도 됨
177+ }
178+ } , 15000 ) ; // 서버 heartbeat 간격과 일치 (15초)
179+
180+ return ( ) => {
181+ clearInterval ( heartbeatCheckTimer . current ) ;
182+ } ;
183+ } , [ ] ) ;
184+
185+
186+ useEffect ( ( ) => {
187+ sendMessageRef . current = sendMessage ;
188+ } , [ sendMessage ] ) ;
189+
149190 useEffect ( ( ) => {
150191 disconnectRef . current = disconnect ;
151192 } , [ disconnect ] ) ;
@@ -174,6 +215,7 @@ const GameLayout = () => {
174215 if ( disconnectRef . current ) {
175216 disconnectRef . current ( ) ;
176217 navigate ( '/room' ) ;
218+ localStorage . removeItem ( `enteredRoom_${ roomId } ` ) ;
177219 }
178220 } else {
179221 // '취소'를 누르면 뒤로가기 동작을 무효화하고 현재 페이지에 머무릅니다.
0 commit comments