์ƒ์„ธ ์ปจํ…์ธ 

๋ณธ๋ฌธ ์ œ๋ชฉ

[์€ผ] ํ™”๋ฉด์ด ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋ฐ”๋€Œ์–ด์•ผ ํ•˜๋Š” ์š”๊ตฌ์‚ฌํ•ญ์„ ํ•ด๊ฒฐํ•ด๋ณด์ž (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);

 

 

๋˜ํ•œ, Context๋ฅผ ๋งŒ๋“ค์–ด WebSocket์—ฐ๊ฒฐ์ด ํ•„์š”ํ•œ ํ™”๋ฉด ๋ ˆ์ด์•„์›ƒ์— ์ ์šฉํ•˜์˜€๋‹ค

"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์ด๋ผ๋Š” ํŒŒ์ผ ์ด๋ฆ„์œผ๋กœ ์ •์˜ํ•˜์˜€๋‹ค 

 

ํŽ˜์ด์ง€์— ์—ฐ๊ฒฐ์š”์ฒญํ•˜๊ณ  ํ•ด์ œํ•˜๋Š” ์˜ˆ์‹œ

 

728x90

๊ด€๋ จ๊ธ€ ๋”๋ณด๊ธฐ