Post

Socket을 사용한 Read-Time 채팅 구현하기 - (1) Socket IO 초기 세팅

Socket을 사용한 Read-Time 채팅 구현하기 - (1) Socket IO 초기 세팅

👩‍💻 Socket을 사용한 Real-Time 채팅 구현하기

실시간 채팅을 구현하기 위해서는 WebSocket을 활용해야 하며, 이를 보다 쉽게 다룰 수 있도록 해주는 라이브러리가 Socket.IO이다. 이번 글에서는 Next.js에서 Socket.IO를 활용하여 실시간 채팅을 구축하는 초기 설정 방법을 다룬다.


1️⃣ Socket.IO 초기 세팅

1. Socket.IO 패키지 설치

먼저 실시간 통신을 위해 Socket.IO 패키지를 설치한다.

1
npm install socket.io socket.io-client

또는

1
2
"socket.io": "^4.8.1",
"socket.io-client": "^4.8.1"

2. Socket.IO 서버 설정

Next.js의 API 라우트를 활용하여 Socket.IO 서버를 설정한다. 먼저 /pages/api/socket 폴더를 생성하고, io.ts 파일을 만든다.

io.ts - Socket.IO 서버 초기화

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// pages/api/socket/io.ts
import { Server as NetServer } from "http";
import { NextApiRequest } from "next";
import { Server as ServerIO } from "socket.io";
import { NextApiResponseServerIo } from "@/types";

// Next.js 기본 bodyParser 비활성화
export const config = {
  api: {
    bodyParser: false
  }
};

const ioHandler = (req: NextApiRequest, res: NextApiResponseServerIo) => {
  if (!res.socket.server.io) {
    const path = "/api/socket/io"; // WebSocket 연결 경로
    const httpServer: NetServer = res.socket.server as any;
    const io = new ServerIO(httpServer, {
      path: path,
      addTrailingSlash: false
    });

    res.socket.server.io = io;
  }
  res.end();
};

export default ioHandler;

types.ts - 커스텀 타입 추가

기본 Next.js NextApiResponse는 Socket.IO 속성을 포함하지 않기 때문에 확장하여 사용한다.

1
2
3
4
5
6
7
8
9
10
11
12
// types.ts
import { Server as NetServer, Socket } from "net";
import { NextApiResponse } from "next";
import { Server as SocketIOServer } from "socket.io";

export type NextApiResponseServerIo = NextApiResponse & {
  socket: Socket & {
    server: NetServer & {
      io: SocketIOServer;
    };
  };
};


3. Socket Provider 구현

Next.js에서 Socket.IO를 전역적으로 관리하기 위해 Context API를 활용하여 SocketProvider를 구현한다.

socket-provider.tsx - Socket Provider 생성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// components/providers/socket-provider.tsx
"use client";

import { createContext, useContext, useEffect, useState } from "react";
import { io as ClientIO } from "socket.io-client";

type SocketContextType = {
  socket: any | null;
  isConnected: boolean;
};

const SocketContext = createContext<SocketContextType>({
  socket: null,
  isConnected: false
});

export const useSocket = () => useContext(SocketContext);

export const SocketProvider = ({ children }: { children: React.ReactNode }) => {
  const [socket, setSocket] = useState(null);
  const [isConnected, setIsConnected] = useState(false);

  useEffect(() => {
    const socketInstance = new (ClientIO as any)(
      process.env.NEXT_PUBLIC_SITE_URL!,
      {
        path: "/api/socket/io",
        addTrailingSlash: false
      }
    );

    socketInstance.on("connect", () => setIsConnected(true));
    socketInstance.on("disconnect", () => setIsConnected(false));

    setSocket(socketInstance);

    return () => socketInstance.disconnect();
  }, []);

  return (
    <SocketContext.Provider value=>
      {children}
    </SocketContext.Provider>
  );
};

layout.tsx - 전역적으로 SocketProvider 추가

1
2
3
4
5
6
7
8
9
10
// app/layout.tsx
import { SocketProvider } from "@/components/providers/socket-provider";

export default function RootLayout({
  children
}: {
  children: React.ReactNode;
}) {
  return <SocketProvider>{children}</SocketProvider>;
}


4. Socket 연결 상태 표시 (Indicator 구현)

실시간 연결 상태를 시각적으로 표시하기 위해 SocketIndicator 컴포넌트를 구현한다.

socket-indicator.tsx - 연결 상태 UI 추가

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// components/socket-indicator.tsx
"use client";

import { useSocket } from "./providers/socket-provider";
import { Badge } from "@/components/ui/badge";

export const SocketIndicator = () => {
  const { isConnected } = useSocket();

  return (
    <Badge
      variant="outline"
      className={isConnected ? "bg-emerald-600" : "bg-yellow-600"}
    >
      {isConnected ? "Live: Real-time updates" : "Fallback: Polling every 1s"}
    </Badge>
  );
};

chat-header.tsx - 채팅 헤더에 표시

1
2
3
4
5
6
7
// components/chat/chat-header.tsx
import { SocketIndicator } from "@/components/socket-indicator";
...
<div className="ml-auto flex items-center">
  <SocketIndicator />
</div>
...


✅ 마무리

이번 글에서는 Next.js에서 Socket.IO를 활용한 실시간 채팅 기능을 구현하기 위한 초기 세팅을 진행했다.

Socket.IO 서버를 API Route로 설정하고, ✅ SocketProvider를 만들어 전역적으로 관리하며, ✅ 실시간 연결 상태를 SocketIndicator를 통해 표시하는 구조를 갖추었다.

This post is licensed under CC BY 4.0 by the author.