소켓을 배웠으니 이번 프로젝트에 적용해보자
그 전에 namespace 와 room 에 대해 알고가야한다
[SOCKET] 📚 Namespace & Room 기능 이해하기
위 블로그를 보고 이해한거는
Namespace = 채널
Room = 방
느낌이다
현재 진행중인 프로젝트에는 방하나에 2명만들어가서 1대1 채팅이기에 서로가 있는 roomId방에만 채팅을 보내면 된다
// 소켓스테이트 생성
const [socket, setSocket] = useState<Socket | null>(null);
원래는 socekt 변수를 생성하고 거기에 바로 서버에 소켓을 연결했는데,
채팅을 치거나, 칠때마다 화면에 렌더링 되면서 socket을 계~~~속해서 재연결을 시켜줬다
무한 응답요청이 일어난거임.
그래서 스테이트 값을 만들어서 연결이 되었을 경우에는 다시 재연결하지 않도록했다.
// ... 중간 코드 생략
useEffect(() => {
const connectSocket = () => {
const socketServer = io("https://ikw-market.shop/chat");
socketServer.on("connect_error", (error) => {
console.error("Socket connection failed:", error);
setConnected(false);
});
socketServer.emit("enter_room", { roomId });
setConnected(true);
setSocket(socketServer);
// 컴포넌트 언마운트시 실행되는 함수
return () => {
if (socketServer) {
socketServer.disconnect();
setConnected(false);
}
};
};
if (!isLogin) {
navigate("/login");
} else {
return connectSocket();
}
}, [navigate, isLogin]);
소켓과 연결이 된다면 roomId에 접속 할 수 있게 된다
그리고 언마운트, 페이지를 나가거나 새로고침을 할 경우 소켓을 연결 해제한다
// io.of() 채널 만들어주는 메서드, "/chat 채널"
const chat = io.of("/chat").on("connection", (socket) => {
console.log("Socket connected!");
//console.log("socket rooms : ", socket.rooms);
socket.on("enter_room", ({ roomId }) => {
// "socket join 메서드를 사용하면 인자로 전달한 방으로 연결."
socket.join(roomId);
});
// 클라이언트에서 연결 해제 이벤트를 처리
socket.on("disconnect", () => {
console.log("Socket disconnected!");
});
socket.on("message", (message, { roomId }) => {
//해당 채팅방으로 메시지를 보낸다.
chat.to(roomId).emit("message", message);
// io.emit("message", { name, message });
});
});
서버는 간단하다. 클라이언트로부터 이벤트를 받았을때, 해당 이벤트의 콜백함수를 호출하고
호출문에는 해당방에 이벤트명과 매개변수(메시지데이터)를 클라이언트로 보내는 emit을 실행시킨다
메시지를 주고 받은 내역들을 볼 수 있도록 데이터베이스에 저장하고 불러올수있게 해줘야 한다
메시지를 보냈을때 소켓에 전달하고 데이터베이스에 저장하는 함수를 호출한다
roomId = 채팅방의ID 이기에 해당 채팅방에 메시지데이터들을 저장하고 데이터베이스에 저장
불러올때도 roomId을 이용해 받아 올 수 있다.
// 메시지를 보냈을 때 발생하는 함수
const writeMessageLogAPI = async (message: IChatMessage) => {
const { state } = await (
await axios.post(`https://ikw-market.shop/api/chats/chat/${roomId}`, { message }, { withCredentials: true })
).data;
};
// 메시지 불러오기
const readChatRoomMessageAPI = async () => {
const { state, chatRoom } = await (
await axios.get(`https://ikw-market.shop/api/chats/${roomId}`, { withCredentials: true })
).data;
setChat([...chatRoom.message_log]);
};