실시간 채팅은 구매자와 판매자 간의 원활한 소통을 위한 필수 기능 중 하나입니다. Next.js와 WebSocket을 활용하여 양방향 통신 기반의 실시간 채팅 애플리케이션을 구현했습니다.
두 개의 주요 컴포넌트로 구성됩니다
1.ChatList
: 사용자의 채팅 목록을 표시하고 관리합니다.
2.ChatRoom
: 실제 채팅이 이루어지는 공간으로, WebSocket 연결을 관리합니다.
ChatList 컴포넌트는 사용자의 채팅 목록을 표시하고, 필터링 기능을 제공합니다.
import React, { useState, useEffect } from 'react';
import useAuthStore from '@/stores/authStore';
import { Chat } from '@/types/chat';
import { MessageSquare } from 'lucide-react';
import Link from 'next/link';
export interface ChatListProps {
initialChats: Chat[];
selectedChatId: number | null;
onChatCreated?: (newChat: Chat) => void;
}
type FilterType = 'all' | 'buy' | 'sell';
const ChatList: React.FC<ChatListProps> = ({ initialChats, selectedChatId }) => {
const { user } = useAuthStore();
const myName = user?.username;
const [filteredChats, setFilteredChats] = useState(initialChats);
const [activeFilter, setActiveFilter] = useState<FilterType>('all');
// ... (필터링 로직 및 UI 렌더링 코드)
return (
<div className="h-full border-r border-[#d9d9d9] bg-white flex flex-col">
{/* ... (필터 버튼 및 채팅 목록 UI) */}
</div>
);
};
export default ChatList;
ChatRoom 컴포넌트는 WebSocket을 사용하여 실시간 채팅 기능을 구현합니다.
import useAccessToken from '@/hooks/useAccessToken';
import React, { useEffect, useRef, useState, useCallback, useLayoutEffect } from 'react';
import { Send } from 'lucide-react';
import useAuthStore from '@/stores/authStore';
import { ChatRoomProps, Message } from '@/types/chat';
const ChatRoom: React.FC<ChatRoomProps> = ({ chatId }) => {
const socketRef = useRef<WebSocket | null>(null);
const [isConnected, setIsConnected] = useState<boolean>(false);
const [messages, setMessages] = useState<Message[]>([]);
const [inputMessage, setInputMessage] = useState<string>('');
// ... (WebSocket 연결 및 메시지 처리 로직)
return (
<div className="flex flex-col h-full bg-white">
{/* ... (메시지 표시 및 입력 UI) */}
</div>
);
};
export default ChatRoom;
ChatRoom 컴포넌트에서 WebSocket 연결을 관리하는 방법을 자세히 살펴보겠습니다.
const connect = useCallback(() => {
if (!accessToken) return;
socketRef.current = new WebSocket(
`${process.env.NEXT_PUBLIC_WS_URL}/${chatId}/?token=${encodeURIComponent(accessToken)}`,
);
socketRef.current.onopen = () => {
setIsConnected(true);
// ... (연결 성공 처리)
};
socketRef.current.onmessage = event => {
// ... (메시지 수신 및 처리)
};
socketRef.current.onerror = error => {
console.error('WebSocket error:', error);
setIsConnected(false);
};
socketRef.current.onclose = () => {
setIsConnected(false);
// ... (재연결 로직)
};
}, [accessToken, chatId]);
useEffect(() => {
connect();
return () => {
disconnect();
};
}, [connect, disconnect]);
메시지 송수신은 다음과 같이 구현됩니다.
const sendMessage = () => {
if (
socketRef.current &&
socketRef.current.readyState === WebSocket.OPEN &&
inputMessage.trim()
) {
const messageData = {
message: inputMessage,
sender: myName,
};
socketRef.current.send(JSON.stringify(messageData));
setInputMessage('');
}
};
// 메시지 수신 처리 (socketRef.current.onmessage 내부)
const newMessage: Message = {
id: data.id?.toString() || Date.now().toString(),
content: data.message || '',
sender: (typeof data.sender === 'object' ? data.sender.username : data.sender) || 'Unknown',
createdAt: new Date(data.created_at || Date.now()),
chatRoom: data.chat_room_id?.toString() || chatId,
};
setMessages(prev => [...prev, newMessage]);
✅ 참고
웹소켓.. 실시간 채팅... 메모.....