개발공부일지
[react-project] socket.io로 실시간 채팅 구현하기 본문
※※ 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 더 공부하기!!!!
'Project' 카테고리의 다른 글
[Project] - React + TypeScript + Tailwind css (0) | 2024.02.16 |
---|---|
[react-project] stacker labs (1) | 2024.01.03 |
[react-project] input box 초기화 (0) | 2023.12.29 |
[react-project] Darkmode 만들기 (tailwind, recoil) (1) | 2023.12.22 |
[react-project] Search Bar 만들기 (0) | 2023.12.20 |