0Pricing
React Academy · 강의

실시간 채팅 컴포넌트 만들기

WebSocket 이벤트와 React 상태를 사용해 스크롤되는 채팅 목록에 실시간 메시지를 표시합니다.

실시간 채팅 컴포넌트 만들기은(는) CoddyKit의 무료 React Academy 강의입니다. 이것은 4개 중 3번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 React Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. React Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

채팅 컴포넌트 아키텍처

실시간 채팅은 메시지 목록(표시), 메시지 입력(전송), WebSocket/Socket.IO 연결 계층의 세 부분으로 구성됩니다. 소켓 로직은 사용자 지정 훅에 두십시오.

메시지 데이터 형태

채팅 메시지에 대한 TypeScript 인터페이스를 정의하여 컴포넌트 전체에서 타입 안전성을 유지하십시오.

interface Message {
  id: string;
  text: string;
  sender: string;
  timestamp: number;
}

const [messages, setMessages] = useState<Message[]>([]);

useChat 훅

연결, 메시지 상태, 전송 함수를 하나의 훅으로 캡슐화하십시오.

function useChat(roomId: string) {
  const [messages, setMessages] = useState<Message[]>([]);

  useEffect(() => {
    socket.connect();
    socket.emit('join-room', roomId);
    socket.on('message', (msg: Message) => setMessages(m => [...m, msg]));
    return () => {
      socket.off('message');
      socket.emit('leave-room', roomId);
      socket.disconnect();
    };
  }, [roomId]);

  const sendMessage = useCallback((text: string) => {
    const msg: Message = { id: crypto.randomUUID(), text, sender: 'me', timestamp: Date.now() };
    socket.emit('message', msg);
  }, []);

  return { messages, sendMessage };
}

메시지 목록 컴포넌트

스크롤할 수 있는 목록에 메시지를 렌더링하십시오. 하단 감시 요소에 useRef를 사용하고 새 메시지가 도착하면 해당 요소로 스크롤하십시오.

function MessageList({ messages }: { messages: Message[] }) {
  const bottomRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    bottomRef.current?.scrollIntoView({ behavior: 'smooth' });
  }, [messages]);

  return (
    <div className="message-list">
      {messages.map(msg => (
        <div key={msg.id} className={`msg ${msg.sender === 'me' ? 'mine' : 'theirs'}`}>
          <span>{msg.sender}</span>
          <p>{msg.text}</p>
        </div>
      ))}
      <div ref={bottomRef} />
    </div>
  );
}

메시지 입력 컴포넌트

Enter 키를 누르거나 button을 클릭할 때 이벤트를 발생시키는 제어 입력입니다. 보낸 후 입력을 지우십시오.

function MessageInput({ onSend }: { onSend: (text: string) => void }) {
  const [text, setText] = useState('');

  const handleSend = () => {
    if (!text.trim()) return;
    onSend(text.trim());
    setText('');
  };

  return (
    <div className="input-row">
      <input
        value={text}
        onChange={e => setText(e.target.value)}
        onKeyDown={e => e.key === 'Enter' && handleSend()}
        placeholder="Type a message..."
      />
      <button onClick={handleSend}>Send</button>
    </div>
  );
}

채팅 UI 조합

훅과 하위 컴포넌트를 하나의 ChatRoom 컴포넌트로 조합하십시오.

function ChatRoom({ roomId }: { roomId: string }) {
  const { messages, sendMessage } = useChat(roomId);

  return (
    <div className="chat-room">
      <h2>Room: {roomId}</h2>
      <MessageList messages={messages} />
      <MessageInput onSend={sendMessage} />
    </div>
  );
}

optimistic 업데이트

서버가 확인하기 전에 메시지를 로컬 상태에 즉시 추가하여 즉각적인 피드백을 제공하십시오. 서버에서 오류를 반환하면 상태를 조정하거나 메시지를 제거하십시오.

const sendMessage = useCallback((text: string) => {
  const optimistic: Message = { id: crypto.randomUUID(), text, sender: 'me', timestamp: Date.now() };
  setMessages(m => [...m, optimistic]); // instant feedback
  socket.emit('message', optimistic, (err) => {
    if (err) setMessages(m => m.filter(msg => msg.id !== optimistic.id));
  });
}, []);

입력 중 표시기

입력이 변경될 때(디바운스하여) typing 이벤트를 발생시키고 다른 사용자의 입력 중 이벤트를 수신하여 표시기를 보여 주십시오.

const emitTyping = useMemo(() => debounce(() => socket.emit('typing'), 300), []);

useEffect(() => {
  socket.on('user-typing', (user) => setTypingUser(user));
  return () => socket.off('user-typing');
}, []);

메시지 타임스탬프

로케일에 맞게 표시하려면 Intl.DateTimeFormat으로 타임스탬프를 형식화하십시오.

function formatTime(ts: number) {
  return new Intl.DateTimeFormat('en', { hour: '2-digit', minute: '2-digit' }).format(ts);
}

<span className="timestamp">{formatTime(msg.timestamp)}</span>

읽음 확인

사용자가 메시지를 볼 때 read 이벤트를 발생시키고 서버에서 읽음 확인을 수신하여 확인 표시를 보여 주십시오.

가상화된 메시지 목록

채팅 기록이 긴 경우 react-window 또는 react-virtual을 사용하여 메시지 목록을 가상화하고 보이는 행만 렌더링하십시오.

메시지 기록 제한

긴 세션에서 메모리가 제한 없이 증가하지 않도록 상태의 메시지 배열에 상한을 설정하십시오.

socket.on('message', (msg: Message) => {
  setMessages(prev => [...prev.slice(-499), msg]); // keep last 500
});

빠른 확인

채팅 목록에 새 메시지가 도착했을 때 하단 감시용 div 요소로 스크롤하는 목적은 무엇입니까?

복습

소켓 로직을 캡슐화하는 useChat 훅, 자동 스크롤 기능이 있는 MessageList, 전송 후 입력을 지우는 MessageInput으로 실시간 채팅을 구축하십시오. 즉각적인 피드백에는 optimistic 업데이트를 사용하고 메모리 누수를 방지하도록 메시지 기록에 상한을 설정하십시오.

자주 묻는 질문

“실시간 채팅 컴포넌트 만들기” 강의는 무료인가요?

네 — “실시간 채팅 컴포넌트 만들기” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 React Academy 강의 전체를 잠금 해제할 수 있습니다. React Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“실시간 채팅 컴포넌트 만들기”에서 뭘 배우나요?

WebSocket 이벤트와 React 상태를 사용해 스크롤되는 채팅 목록에 실시간 메시지를 표시합니다. 브라우저에서 직접 실행하는 실습 코드로 React Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

React Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 React Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 3번째 강의입니다.

“실시간 채팅 컴포넌트 만들기” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 React Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 React Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 브라우저에서 WebSocket 기초 익히기
  2. React에서 Socket.IO 사용하기
  3. 실시간 채팅 컴포넌트 만들기
  4. 재연결, 오류 처리와 정리
← React Academy(으)로 돌아가기