[์ผ] ํ๋ฉด์ด ์ค์๊ฐ์ผ๋ก ๋ฐ๋์ด์ผ ํ๋ ์๊ตฌ์ฌํญ์ ํด๊ฒฐํด๋ณด์ (2) : ํ๋ก ํธ์ค๋
ํ์๊ฐ์ ํ
(1) ์ ์ ์ ๋ณด ์ ๋ ฅ (2) ๋ถ๋ถ ์ ๋ณด ์ ๋ ฅ
2๊ฐ์ง ์์ ์ ๋ง์ณ์ผ ํ ํ๋ฉด์ ์ง์ ํ ์ ์๋ค.
์๋์ ๊ฐ์ด ํ๋ก ํธ์ค๋ ์ฝ๋์์๋
์
๋ ฅ์ด ํ์ํ ๊ฐ๋ค์ด ์
๋ ฅ๋์๋์ง ์ฌ๋ถ์ ๋ฐ๋ผ status๋ฅผ ๊ฒฐ์ ํ๊ณ
status๊ฐ์ ๊ธฐ์ค์ผ๋ก ํ๋ฉด ์ ํ์ ์งํํ๊ณ ์์๋ค
export type LoginStatusType = 'init' | 'logged' | 'authed' | 'coded' | 'complete';
const [status, setStatus] = useState<LoginStatusType>('init');
if (res.data.spouseInfoAdded && res.data.spouseConnected && res.data.authenticated) {
setStatus('complete');
} else if (!res.data.spouseInfoAdded && res.data.spouseConnected && res.data.authenticated) {
setStatus('coded');
} else if (!res.data.spouseInfoAdded && !res.data.spouseConnected && res.data.authenticated) {
setStatus('authed');
} else if (!res.data.spouseInfoAdded && !res.data.spouseConnected && !res.data.authenticated) {
setStatus('logged');
} else {
setStatus('init');
}
useEffect(() => {
console.log(status);
if (status === 'complete') {
router.replace('/main');
} else if (status === 'coded') {
router.replace('/user/marry/info');
} else if (status === 'authed') {
router.replace('/user/marry/code');
} else if (status === 'logged') {
router.replace('/user/profile');
} else if (status === 'init') {
router.replace('/auth');
}
}, [status]);
์์ผ๋ก ํ๋ฉด ์ ํ ์ ๋ณด๋ ์๋ฒ ์ธก์์ ์ ๊ณตํ ์์ ์ด๊ธฐ ๋๋ฌธ์
์ ์ผ ๋จผ์ ํด๋น ๋ก์ง์ ์๋ฒ๋ก ์ฎ๊ธฐ๊ณ API์ setState ๋ถ๋ถ์ ๋จ์ํ๊ฒ ์์ ํ์๋ค.
import { AppRouterInstance } from "next/dist/shared/lib/app-router-context";
export type LoginStatusType = 'init' | 'logged' | 'authed' | 'coded' | 'complete';
export const loadingActions: Record<LoginStatusType, (router: AppRouterInstance) => void> = {
init: (router) => router.replace('/auth'),
logged: (router) => router.replace('/user/profile'),
authed: (router) => router.replace('/user/marry/code'),
coded: (router) => router.replace('/user/marry/info'),
complete: (router) => router.replace('/main'),
};
loadingActions[status as LoginStatusType](router);
"use client";
import React, { createContext, ReactNode, useContext, useState, useEffect, useRef, useCallback } from 'react';
import SockJS from 'sockjs-client';
import { Client } from '@stomp/stompjs';
import { LoginStatusType } from 'utils/loginUtils';
interface WebSocketContextType {
status: string;
connect: (topic: string) => void;
disconnect: () => void;
updateStatus: LoginStatusType | null;
sendMessage: (destination: string, message: any) => void;
}
const WebSocketContext = createContext<WebSocketContextType | null>(null);
export const WebSocketProvider = ({ children }: { children: ReactNode }) => {
const [status, setStatus] = useState<string>('INCOMPLETE');
const [updateStatus, setUpdateStatus] = useState<LoginStatusType | null>(null);
const socketRef = useRef<Client | null>(null); // useRef๋ก ๋ณ๊ฒฝํ์ฌ ์ํ ๋ณ๊ฒฝ ์์ด ์์ผ์ ๊ด๋ฆฌ
const [reconnectAttempts, setReconnectAttempts] = useState<number>(0); // ์ฌ์ฐ๊ฒฐ ์๋ ํ์
// WebSocket ์ฐ๊ฒฐ ํจ์
const connect = useCallback((topic: string) => {
const socketInstance = new SockJS(`${process.env.NEXT_PUBLIC_API_URL}/back/api/ws`);
const stompClient = new Client({
webSocketFactory: () => socketInstance,
onConnect: () => {
setStatus('CONNECTED');
stompClient.subscribe(topic, (message: any) => {
console.log(message.body)
if (message.body) {
try {
setUpdateStatus(message.body);
} catch (error) {
console.error('Error parsing WebSocket message:', error);
}
}
});
},
onStompError: (error) => {
setStatus('ERROR');
console.error('WebSocket Error: ', error);
if (reconnectAttempts < 3) {
// ์ต๋ 3๋ฒ๊น์ง ์ฌ์ฐ๊ฒฐ ์๋
setReconnectAttempts((prev) => prev + 1);
setTimeout(() => {
connect(topic); // ์ฌ์ฐ๊ฒฐ ์๋
}, 3000);
}
},
});
stompClient.activate();
socketRef.current = stompClient; // useRef๋ก ์์ผ ๊ฐ์ฒด ์ ์ฅ
}, [reconnectAttempts]);
// WebSocket ์ฐ๊ฒฐ ํด์ ํจ์
const disconnect = () => {
if (socketRef.current) {
socketRef.current.deactivate();
socketRef.current = null;
setStatus('DISCONNECTED');
}
};
const sendMessage = (destination: string, message: any) => {
if (socketRef.current && socketRef.current.connected) {
socketRef.current.publish({
destination: destination,
body: JSON.stringify(message),
});
} else {
console.error('WebSocket is not connected.');
}
};
return (
<WebSocketContext.Provider value={{ status, connect, disconnect, updateStatus, sendMessage }}>
{children}
</WebSocketContext.Provider>
);
};
export const useWebSocket = () => {
const context = useContext(WebSocketContext);
if (!context) {
throw new Error('useWebSocket must be used within a WebSocketProvider');
}
return context;
};
๊ทธ๋ฆฌ๊ณ next.js 13๋ฒ์ ์ด์์์ ์๋ฒ์ฌ์ด๋ ๋๋๋ง์ ํ๋ ๊ฒฝ์ฐ
ํด๋ ๊ตฌ์กฐ์ ํ์ผ ์ด๋ฆ์ด url์ ๊ฒฐ์ ํ๋ค
์ ์ฒด ํ์ด์ง๋ฅผ ๋์์ผ๋ก Context๋ ๋์์ธ์ ์ ์ฉํ๊ณ ์ถ์ ๊ฒฝ์ฐ
/app ๋๋ ํ ๋ฆฌ ์ layout์ด๋ผ๋ ํ์ผ์ด๋ฆ์ผ๋ก RootLayout์ ์ ์ํ๋ฉด ๋๋ค
์ด๋ฒ ๊ฒฝ์ฐ์๋ ํน์ ํ์ด์ง์๋ง context๋ฅผ ์ ์ฉํ๊ธฐ ์ํด
์ ์ฉํ ํ์ด์ง๊ฐ ์๋ ๋๋ ํ ๋ฆฌ์ layout์ด๋ผ๋ ํ์ผ ์ด๋ฆ์ผ๋ก ์ ์ํ์๋ค
