프론트는 갈수록 점점 개판이 되어간다.
프론트에서 stomp로 구독후 채팅내용을 수정하면 계속 서버로 info정보를 요청하던데 왜그런지 문제를 찾지 못해서 오래걸렸다.
1. ChatRoomList 작성
const ChatRoomList = () => {
const [chatRoomList, setChatRoomList] = useState();
const [chatRoom, setChatRoom] = useState();
const [targetEmail, setTargetEmail] = useState();
const [clickState, setClickState] = useState();
const onChatRoom = (idx) => {
setChatRoom(chatRoomList[idx].chatRoomId);
}
const onClickChatRoom = (idx) => {
withJwtAxios.get("/chats/create", {params: {target: chatRoomList[idx].email}})
.then((res) => {
let list = res.data.chatRoomList;
setChatRoomList(list);
setChatRoom(list[idx].chatRoomId)
setTargetEmail(list[idx].email)
})
let len = clickState.length;
let temp = new Array(len).fill(false);
temp[idx] = true;
setClickState(temp);
}
useEffect(() => {
withJwtAxios.get("/chats/user-list")
.then((res) => {
setChatRoomList(res.data.chatRoomList);
setClickState(new Array(res.data.chatRoomList.length).fill(false));
});
}, [])
return (
<div className={style.container}>
<div className={style.chat_room_list_container}>
{chatRoomList != undefined ?
chatRoomList.map((chat, idx) => {
return(
<div key={idx} className={style.list_container} onClick={() => onClickChatRoom(idx)} style={clickState[idx] ? {backgroundColor: '#dadada'} : {backgroundColor: 'white'}}>
<img src={Static_Base_Url + chat.profileUrl} className={style.thumbnail}/>
<div className={style.content}>
<div className={style.nickname}>{chat.nickname}</div>
{clickState[idx] ? <></> : <div className={style.last_message}>{chat.lastMessage}</div>}
</div>
</div>
)
})
:
<div></div>
}
</div>
<div className={style.chat_room_container}>
<ChatRoom chatRoomList={chatRoomList} chatRoom={chatRoom} targetEmail={targetEmail}/>
</div>
</div>
);
};
export default ChatRoomList;
- 이 컴포넌트는 채팅 유저 목록을 랜더링해주는 함수이다.
- 특정 채팅방을 선택하면 채팅방 Id와 채팅유저를 props로 넘겨준다.
2. ChatRoom.js 작성
const ChatRoom = (props) => {
const chatRoomId = props.chatRoom;
const targetEmail = props.targetEmail;
const [inputs, setInputs] = useState("");
const [chatting, setChatting] = useState();
const [chatList, setChatList] = useState();
const userDetail = useSelector(state => state.userDetail);
const stomp = useRef({});
const sock = new SockJs("http://localhost:8080/api/socket");
stomp.current = Stomp.over(sock);
const headers = {
'Authorization': localStorage.getItem("accessToken")
}
const onSubmit = () => {
let value = JSON.stringify(inputs);
value = value.slice(1, value.length-1)
if(value) {
const data = {
chatRoomId: chatRoomId,
message: inputs
}
withJwtAxios.post("/chats/chat", data)
.then((res) => {
setChatList(res.data.chatList);
});
stomp.current.send("/publish/messages", headers, JSON.stringify({
message: inputs,
senderEmail: userDetail.email,
receiverEmail: targetEmail,
chatRoomId: chatRoomId
}), (res) => {
console.log(res.data.body);
})
setInputs("");
}
}
const onKeyPress = (e) => {
if(e.key == 'Enter') {
onSubmit();
}
}
useEffect(() => {
if(chatRoomId != undefined) {
withJwtAxios.get("/chats/chat-list", {params: {chatRoomId: chatRoomId}})
.then((res) => {
setChatList(res.data.chatList);
})
stomp.current.connect(headers, () => {
stomp.current.subscribe('/subscribe/rooms/' + chatRoomId, (res) => {
const obj = JSON.parse(res.body)
// console.log(obj)
setChatting({
email: obj.email,
nickname: obj.nickname,
profileUrl: obj.profileUrl,
content: obj.content
})
}, headers)
});
}
}, [chatRoomId])
useEffect(() => {
if(chatList != undefined) {
let tmp = [...chatList];
tmp.push(chatting);
setChatList(tmp);
}
}, [chatting])
const onChange = (e) => {
setInputs(e.target.value);
}
return (
<>
<div className={style.chat_body_container}>
<div>
{chatList != undefined ? chatList.map((chat, idx) => {
if(chat.email === userDetail.email) {
return(
<div key={idx} className={style.my_chat}>
<div className={style.my_chat_box}>
{chat.content}
</div>
</div>
)
} else {
if(idx > 0) {
return(
<div key={idx} className={style.oppo_chat}>
{chatList[idx-1].email !== chat.email ?
<img className={style.thumbnail} src={Static_Base_Url + chat.profileUrl} /> :
<div className={style.thumbnail_blank}></div>}
<div className={style.oppo_chat_box}>
{chat.content}
</div>
</div>
)
} else {
return(
<div key={idx} className={style.oppo_chat}>
<img className={style.thumbnail} src={Static_Base_Url + chat.profileUrl} />
<div className={style.oppo_chat_box}>
{chat.content}
</div>
</div>
)
}
}
}) :
<div></div>
}
</div>
</div>
<div className={style.input_container}>
<input className={style.input} value={inputs} onChange={onChange} onKeyPress={onKeyPress}/>
<button className='btn btn-outline-primary' onClick={onSubmit}>보내기</button>
</div>
</>
);
};
export default ChatRoom;
- 랜더링 되면, SockJs로 백엔드 서버와 소켓 연결을 한 후 채팅방 ID정보를 토대로 구독을 진행한다.
- 그리고 stomp의 send메서드로 내용을 보내고, subscribe에 구독 후 메세지 응답이 발생 했을 때의 로직을 설정해준다.
3. 동작모습
코드는 간단한데, 전혀 처음 접하는 개념이라 좀 이상할 수도 있다.
'Web > 인스타 클론 코딩' 카테고리의 다른 글
[인스타그램 클론코딩] 13. 게시글 검색 기능 구현(Front-End) (0) | 2023.02.16 |
---|---|
[인스타그램 클론코딩] 13. 게시글 검색 기능 구현(Back-End) (0) | 2023.02.16 |
[인스타그램 클론코딩] 12. 메신저 기능 구현(Back-End) (0) | 2023.02.16 |
[인스타그램 클론코딩] 11. 프로필 수정 기능 구현(Front-End) (0) | 2023.02.07 |
[인스타그램 클론코딩] 11. 프로필 수정 기능 구현(Back-End) (0) | 2023.02.07 |