Notice
Recent Posts
Recent Comments
Link
«   2024/12   »
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
Tags
more
Archives
Today
Total
관리 메뉴

개발공부일지

[react-project] socket.io로 실시간 채팅 구현하기 본문

Project

[react-project] socket.io로 실시간 채팅 구현하기

보람- 2023. 12. 29. 16:27

※※  socket.io

https://socket.io/docs/v4/tutorial/introduction

 

※※ 참고

https://github.com/subinkr/simple-chat

 

 

 

** 프로젝트 내용 중 유저를 follow했다면 채팅이 가능하도록 만들었다.

- 유저간의 follow가 이루어지면 user data안에서 rooms가 만들어지고 그걸 토대로

- follow list를 만들어 먼저 친구 목록을 보여주었다.

- 친구목록에서 채팅하고싶은 유저의 정보와 채팅할수있는 아이콘을 만들었고

- 아이콘을 누르면 채팅창이 나타난다.

 

 

 ** Atomic Design Pattern으로 작업!

 

 

- MainPage 중 가장 오른쪽 아래에 위치해 있는 채팅 아이콘!

  - follow목록을 숨겨두고 위의 이미지 아이콘만 보이게 만들어두고

  - 아이콘을 클릭했을때 친구 목록이 나타나고, 비행기 아이콘이 X로 변한다.

      (로그인이 되어있어야함!)

 

- follow 해둔 유저가 있다면 유저의 목록들이 뜨고 없다면 follow 유저가 없다고 뜬다.

 

- 유저 목록에는 follow해둔 유저의 이미지, 닉네임, 채팅 아이콘이 있음

   - 이미지, 닉네임을 누르면 유저페이지로 넘어가고

   - 채팅 아이콘을 누른다면 채팅창이 나타난다.

 

- 채팅아이콘을 눌렀다면 socket.io를 사용해서 서버에 요청을 하는데

  - useEffect을 사용해서 소켓을 초기화하고, 채팅 메시지를 업데이트하고
  - getChats 함수를 만들어 서버로부터 이전 채팅 내용을 가져와 화면에 보여주고
  - sendMessage 함수를 만들어서 사용자가 작성한 메시지를 소켓을 통해 전송하고, 화면에 보여주고!

  - 유저 정보에 따라 작성자는 오른쪽, 상대방은 왼쪽에 메세지가 보여진다.

   ( 채팅이 길어진다면 스크롤바 생성이 된다. input box 입력값 초기화 )

  → 실시간 채팅 가능!

 

 

 

** socket.io-client 실시간 양방향 통신

npm install socket.io
npm install socket.io-client



** chatting 컴포넌트 코드

import React, { useEffect, useRef, useState } from "react";
import axios from "axios";
import { io } from "socket.io-client";
import { useRecoilValue } from "recoil";
import { userState } from "../../recoil/userState";

const Chatting = ({ roomId, nickname, image }) => {
  const { user } = useRecoilValue(userState);
  const inputRef = useRef(null);
  const chatRef = useRef(null);
  const [socket, setSocket] = useState(null);
  const [chat, setChat] = useState(null);
  const [chatLoad, setChatLoad] = useState(false);
  const [inputValue, setInputValue] = useState("");

  useEffect(() => {
    if (!socket) {
      setSocket(io(`wss://api.subin.kr/room/${roomId}`));
    } else {
      socket.on(`${roomId}`, (data) => {
        setChat(data);
      });

      if (!chatLoad) {
        const getChats = async () => {
          try {
            const response = await axios.get(
              `${process.env.REACT_APP_API_SERVER}/room/${roomId}`,
              { withCredentials: true }
            );
            const result = response.data;
            // 지난대화 내용이 보여져야햠!
            if (result.length > 0) {
              result.forEach((chat) => {
                const chatDiv = document.createElement("div");
                chatDiv.innerText = `${chat.content}`;
                chatDiv.className =
                  user.id === chat.user.id ? "text-right p-1" : "text-left p-1";
                chatRef.current.appendChild(chatDiv);
              });
              setChatLoad(true);
            } else {
              chatRef.current.style.overflowY = "hidden";
            }
          } catch (error) {
            console.log(`error :`, error);
          }
        };
        getChats();
      }
    }
  }, [socket, chatLoad]);

  useEffect(() => {
    if (chat) {
      // 현재 대화내용
      const chatDiv = document.createElement("div");
      chatDiv.innerText = `${chat.content}`;
      chatDiv.className =
        user.id === chat.user.id ? "text-right p-1" : "text-left p-1";
      chatRef.current.appendChild(chatDiv);
      chatRef.current.scrollTop = chatRef.current.scrollHeight;
    }
  }, [chat]);

  const sendMessage = () => {
    socket.emit("send-message", {
      user: {
        id: user.id,
      },
      content: inputValue,
    });
    setChat({
      user: {
        id: user.id,
      },
      content: inputValue,
    });
    setInputValue("");
  };

  return (
    <div>
      <div>
        <div>
          <div>
            <img src={image} alt="" />
          </div>
          <div>{nickname}</div>
        </div>
        <div>
          <div
            ref={chatRef}
            className={cn(
              "text-lg p-3 w-full h-[550px] overflow-y-scroll scrollbar-hide",
              "note:h-[335px]"
            )}
          ></div>
          <input
            placeholder="chat..."
            ref={inputRef}
            value={inputValue}
            onChange={(e) => setInputValue(e.target.value)}
            onKeyDown={(e) => {
              if (e.key === "Enter") {
                sendMessage();
              }
            }}
            className="w-full text-black h-[35px] rounded-md px-2 outline-none border-none"
          />
        </div>
      </div>
    </div>
  );
};

export default Chatting;

 

 


※ socket 더 공부하기!!!!