채팅방 디자인을 어떻게 하는게 좋을까?
디스코드 같은 디자인으로,
왼쪽에 채팅방 리스트, 오른쪽에 채팅 리스트를 넣고 디스코드처럼 채팅방 리스트 최상단에 채팅방 추가 버튼을 넣는 게 좋을 것 같다.
채팅방 리스트 목록 디자인하기
shadcn/ui를 참고해서,
왼쪽에는 저런 리스트 형태로 채팅방 리스트가 있고 오른쪽에는 채팅창 화면이 보이게 할 예정이다.
더미 데이터를 만들었다.
const chatRooms = [
{
id: 1,
name: "일반 채팅방",
participants: 15,
lastMessage: "안녕하세요!",
lastActivityTime: "방금 전",
unreadCount: 3,
lastSender: {
name: "김철수",
avatar: "./../public/image/profile.png",
},
},
{
id: 2,
name: "개발자 모임",
participants: 8,
lastMessage: "리액트 너무 재밌어요",
lastActivityTime: "5분 전",
unreadCount: 0,
lastSender: {
name: "이영희",
avatar: "",
},
},
{
id: 3,
name: "취미 공유방",
participants: 23,
lastMessage: "저도 같이 하고 싶어요",
lastActivityTime: "30분 전",
isPrivate: false,
unreadCount: 5,
lastSender: {
name: "박지민",
avatar: "",
},
},
];
그리고 shadcn/ui의 Avatar을 이용해서 임시로 프로필 사진과 프로필 사진이 없을 경우 닉네임의 첫글자가 보이게 했다.
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Badge } from "@/components/ui/badge";
const ChatRoomList = () => {
const chatRooms = [
{
id: 1,
name: "일반 채팅방",
participants: 15,
lastMessage: "안녕하세요!",
lastActivityTime: "방금 전",
unreadCount: 3,
lastSender: {
name: "김철수",
avatar: "./../public/image/profile.png",
},
},
{
id: 2,
name: "개발자 모임",
participants: 8,
lastMessage: "리액트 너무 재밌어요",
lastActivityTime: "5분 전",
unreadCount: 0,
lastSender: {
name: "이영희",
avatar: "",
},
},
{
id: 3,
name: "취미 공유방",
participants: 23,
lastMessage: "저도 같이 하고 싶어요",
lastActivityTime: "30분 전",
unreadCount: 5,
lastSender: {
name: "박지민",
avatar: "",
},
},
];
return (
<div className="p-4">
{chatRooms.map((chatRoom) => (
<div
key={chatRoom.id}
className="flex items-center justify-between p-5 border-b hover:bg-slate-50 cursor-pointer"
>
<div className="flex items-center gap-4 flex-1">
<Avatar>
<AvatarImage src={chatRoom.lastSender.avatar} />
<AvatarFallback>{chatRoom.lastSender.name[0]}</AvatarFallback>
</Avatar>
<div className="flex flex-col gap-1 flex-1">
<div className="flex items-center gap-2">
<span className="font-medium">{chatRoom.name}</span>
<span className="font-light text-xs text-gray-500">
{chatRoom.participants}명
</span>
</div>
<div className="flex items-center gap-1 text-sm text-gray-500">
<span className="line-clamp-1 max-w-[200px]">
{chatRoom.lastMessage}
</span>
</div>
</div>
</div>
<div className="flex flex-col items-end gap-2 min-w-[80px]">
<span className="text-xs text-gray-500">
{chatRoom.lastActivityTime}
</span>
{chatRoom.unreadCount > 0 && (
<Badge variant="destructive" className="rounded-full">
{chatRoom.unreadCount}
</Badge>
)}
</div>
</div>
))}
</div>
);
};
export default ChatRoomList;
디자인은 다 끝났다!
이제 api를 연결해보자.
axios로 api 연동하기
axios 설치하기
npm install axios
axios란 무엇인가요?
api를 연동할 수 있는 방법은 fetch를 이용하는 방법과 axios를 이용하는 방법 2가지가 있다.
Next.js를 썼을 때는 fetch를 이용해야 캐싱 기능을 활용할 수 있어서 별 고민 없이 fetch를 이용했는데, 리액트에서는 axios를 사용하는 경우가 많은 것 같아서 왜 그런지? 알아보려고 한다.
https://axios-http.com/kr/docs/intro
fetch는 응답을 처리할 때 respose.json()으로 매번 JSON 형식으로 바꿔주는 작업이 필요한데, axios는 이런 처리를 자동으로 해준다. 또한 HTTP 에러 상태코드를 받았을 때, 조금 더 간단하게 에러를 처리할 수 있다는 장점이 있다고 한다.
사실 이런 부분은 말만 들어서는 잘 모르고 직접 써봐야 안다.
그래서 써봐야겠다.
사실 이전 프로젝트에서 fetch를 썼을 때도 모듈화 된 api를 이용했어서 에러처리가 그렇게 불편한지는...? 별로 못느낀 것 같다.
그래도 새로운 것을 써보고 싶기 때문에 axios를 사용해보도록 하자.
api 인스턴스 만들기
const api = axios.create({
baseURL: "<http://localhost:3001/api>",
timeout: 5000,
headers: {
"Content-Type": "application/json",
},
});
axios를 사용하며 header에 토큰을 넣거나 param을 넣을 일이 많을 것 같은데, 재사용하기 좋아보여서 api instance를 만들어보았다.
const [chatRooms, setChatRooms] = useState<ChatRoom[]>([]);
const fetchChatRooms = async () => {
try {
const response = await api.get<ChatRoom[]>("/rooms");
setChatRooms(response.data);
} catch (error) {
if (axios.isAxiosError(error)) {
const errorMessage =
error.response?.data?.error ||
"채팅방 목록을 불러오는데 실패했습니다.";
console.error(errorMessage);
} else {
console.error("알 수 없는 에러가 발생했습니다.");
}
}
};
useEffect(() => {
fetchChatRooms();
}, []);
fetchChatRooms 내에서 axios를 이용해 get 호출을 하고 받은 데이터를 chatRooms state에 저장한다. 에러 핸들링도 해보았다.
const fetchChatRooms = async () => {
const result = await getChatRooms();
setChatRooms(result);
};
import axios from "axios";
const api = axios.create({
baseURL: "<http://localhost:3001/api>",
timeout: 5000,
headers: {
"Content-Type": "application/json",
},
});
const handleError = (error: unknown) => {
if (axios.isAxiosError(error)) {
console.error(error.response?.data?.error);
} else {
console.error("알 수 없는 에러가 발생했습니다.");
}
};
export const getChatRooms = async () => {
try {
const response = await api.get("/rooms");
return response.data;
} catch (error) {
handleError(error);
}
};
에러를 처리할 수 있는 부분이 반복될 것 같아 함수를 분리했다.
컴포넌트 내에서는 getChatRooms 한줄만 쓰면 데이터를 받아올 수 있다!
'프로젝트 > chat-app' 카테고리의 다른 글
react-router로 채팅방 라우팅하기 (0) | 2024.12.10 |
---|---|
shadcn/ui 도입하기 (1) | 2024.12.06 |
채팅방 스키마, API 만들기 (mongoDB, thunderClient) (0) | 2024.12.05 |
채팅 앱 mongoDB 연결하기 (0) | 2024.12.05 |
react+socket.io로 채팅 앱 구현하기 (1) | 2024.12.04 |