독서 감사 공유 플랫폼(이하 bovo 프로젝트)을 개발하면서 나의 토론방 리스트에서 클릭시 이미 참여했던 토론방에 대해서는 바로 입장 가능하도록 개발하고 있었으나 항상 "방 참여에 실패했습니다."라는 문구가 출력되면서 입장이 불가했었다.
| 내 토론방 리스트 화면 |
|
초기에는 백엔드 팀원분이 서버의 controller 코드 문제로 인해 입장이 불가했을 것이라는 의견이 있어서 문제가 해결될 때까지 기다렸으나, 이미 서버가 배포된 이후에도 문제가 지속됨에 따라 화면단 코드에 문제가 있을 것이라는 의심이 증폭됐다.
실제로 코드를 분석해보니 기본적인 부분에서 잘못되었다.
현재 내 토론방 리스트에서 토론방으로 입장하기까지의 과정은 다음과 같다.
1. MyForumList 컴포넌트에서 handleRoomClick 함수를 통해fetchMyRoomData(roomId)를 호출
2. fetchMyRoomData 함수는 api.get(/chatrooms/my/${roomId})를 호출한 후, 그 응답인 response.data를 그대로 반환
3. /chatrooms/my/{roomId} API가 채팅방에 기록되었던 message data를 반환
여기서 실제 데이터 통신을 하는 fetchMyRoomData 함수는 다음과 같다.
// 나의토론방 참여를 위한 데이터 요청
export const fetchMyRoomData = async (roomId) => {
const response = await api.get(`/chatrooms/my/${roomId}`);
return response.data;
};
그리고 이 반환된 response.data를 사용하는 handleRoomClick 함수는
const MyForumList = ({myChatroom}) => {
const dispatch = useDispatch();
const navigate = useNavigate();
// ✅ formatDate 함수 사용하여 날짜 포맷팅
const formattedDate = formatDate(myChatroom.last_msg_info.last_message_date);
const handleRoomClick = async (roomId, roomName) => {
try {
const response = await fetchMyRoomData(roomId);
console.log("채팅방 참여 api", response);
if (response.status === 200) {
toast.success(`${myChatroom.chatroom_name}방에 성공적으로 참여했습니다.`);
// 서버에서 받은 메시지를 Redux 상태에 추가
response.data.forEach((message) => {
dispatch(addMessage(message));
});
// 서버에서 받은 메시지를 sessionStorage에도 저장 (새로고침 시 복원 가능)
sessionStorage.setItem("chatMessages", JSON.stringify(response));
// Redux에 저장된 메시지를 사용하므로 navigate의 state는 필요 없음
navigate(`/forum/${roomId}`, { state: { roomName: roomName } });
} else {
toast.error("방 참여에 실패했습니다.");
}
} catch (error) {
console.error("방 참여 오류:", error);
toast.error("방 참여 중 오류가 발생했습니다.");
}
};
문제가 되는 지점은 fetchMyRoomData 함수에서는 response.data를 반환하는데 반해 그 response.data를 사용하는 MyForumList컴포넌트의 handleRoomClick에서는 response의 성분 중 하나인 response.status를 사용하고 있다. 이에 따라 반환된 data에 없는 status를 조건문으로 걸고, 이때에만 입장이 가능하도록 설정함으로써 계속해서 내 토론방 리스트에서는 토론방 입장이 실패하는 에러가 발생한 것이다.
실제 response 객체를 console로 출력하여 살펴보면 다음과 같다.

// Axios 응답 객체 예시
{
data: { /* 실제 서버 응답 본문 데이터 */ },
status: 200, // HTTP 상태 코드
statusText: 'OK',
headers: { /* 응답 헤더 */ },
config: { /* 요청 설정 */ },
request: { /* 요청 객체 */ }
}
이후 fetchMyRoomData에서 반환값을 response.data에서 response로 수정하면 될까?
정답은 아니다. 실제로 반환값만 변경하면 다음과 같은 에러가 출력된다.

왜냐하면 반환값이 response로 변경된만큼 handleRoomClick함수에서 sessionStorage에 저장되는 message도 response.data로 변경해야 하며,
현재의 조건문은 단순히 status에 따라 토론방 입장만 처리하는 반면에 메시지가 없을 경우에 forEach를 돌릴 수 없으므로 data가 존재하는지도 조건을 검사하여야 한다.
이에 따라 fetchMyRoomData함수와 handleRoomClick함수는 다음과 같이 변경해야 한다.
// 나의토론방 참여를 위한 데이터 요청
export const fetchMyRoomData = async (roomId) => {
const response = await api.get(`/chatrooms/my/${roomId}`);
return response;
};
const MyForumList = ({myChatroom}) => {
const dispatch = useDispatch();
const navigate = useNavigate();
// ✅ formatDate 함수 사용하여 날짜 포맷팅
const formattedDate = formatDate(myChatroom.last_msg_info.last_message_date);
const handleRoomClick = async (roomId, roomName) => {
try {
const response = await fetchMyRoomData(roomId);
console.log("채팅방 참여 api", response);
if (response.status === 200) {
// 서버 응답 데이터 (response.data)가 유효한 배열인지 확인
if (response.data && Array.isArray(response.data)) {
if (response.data.length > 0) {
toast.success(`${myChatroom.chatroom_name}방에 성공적으로 참여했습니다.`);
// 서버에서 받은 메시지를 Redux 상태에 추가
response.data.forEach((message) => {
dispatch(addMessage(message));
});
} else {
// 메시지가 없는 빈 채팅방에 입장 성공
toast.success(`${myChatroom.chatroom_name}방에 성공적으로 참여했습니다.`);
}
// 서버에서 받은 메시지를 sessionStorage에도 저장
sessionStorage.setItem("chatMessages", JSON.stringify(response.data)); // ⭐ response.data만 저장
navigate(`/forum/${roomId}`, { state: { roomName: roomName } });
} else {
// response.data가 배열이 아니거나 예기치 않은 형식인 경우
console.error("서버 응답 데이터 형식이 올바르지 않습니다:", response.data);
toast.error("방 참여에 실패했습니다: 유효하지 않은 응답 데이터.");
}
} else {
// HTTP 상태 코드가 200이 아닌 경우 (예: 404, 500 등)
toast.error(`방 참여에 실패했습니다. (상태 코드: ${response.status})`);
}
} catch (error) {
// 네트워크 오류나 fetchMyRoomData에서 발생한 기타 오류 처리
console.error("방 참여 중 오류 발생:", error);
toast.error("방 참여 중 오류가 발생했습니다.");
}
};
아무리 실수였더라고 하더라도 내가 무언가를 착각하고 있는 것이 존재하기 때문에 실수한 것이라 생각한다. 물론 첫번째로 response 구성 요소에 대해 익숙지 않은 것이 원인 비중에서 가장 크겠지만, 아마도 데이터 통신 후 data를 바로 꺼내서 사용하고 싶었기에 모듈화된 axios 함수에서 반환 값을 response.data로 바로 반환한 것으로 생각된다.
실무를 접해본적은 없지만 아마도 상황에 따라 팀 컨벤션에 따라 return값을 response로 할 수도 response.data로 할 수도 있을 것으로 추정된다.
다만 이러한 response(응답 객체)에 대해 충분히 익숙해지는 것이 필요하고, 상태 코드에 따라 다른 동작이 필요하거나 response body 이외의 내용이 필요한 경우 등의 상황에서는 response를 필요한 데이터만 추출할 필요성이 있거나 간결한 코드를 가져가는 상황등에서는 response.data를 반환해야겠다.