지난 포스트에서는 회원가입과 로그인 기능을 구현했다.
이번 포스트를 작성하려고 기능을 구현하다보니.. 파이널 프로젝트를 앞두고 혼자 또 프로젝트를 하고 있는 느낌이다
설날에 할 일이 없어서 빈둥빈둥 누워있다가 삘받고 개발하고 반복하고 있다보니 속도가 좀 더딘 감이 있지만 어떻게든 화요일까지 완성은 될 것 같다..?
아무튼 이번 포스트에서는 로그아웃 기능과, 채팅방 리스트 렌더링 및 채팅방 열람 기능까지 구현했다.
로그인 기능이 있다면, 로그아웃 기능도 있어야 한다.
로그아웃은 비교적 간단하게 구현했는데, 포켓호스트에서 스토리지 사용 없이 valid 로직을 수행하는 기능이 있었기 때문이다.
그래도 로그인 상태 유지쪽에서는 문제가 있어서 세션스토리지를 사용해 추가 검증을 구현하고 로그아웃 시 모두 날려주었다.
function ChatRoomList({ userInfo, changeState }) {
...
const handleLogout = () => {
const pb = usePb();
if (confirm('로그아웃 하시겠습니까?')) {
pb.authStore.clear();
sessionStorage.removeItem('token');
changeState(false);
}
};
...
return (
<>
<Header userName={userName} handleLogout={handleLogout} />
...
</>
);
}
채팅방 리스트 컴포넌트에 헤더 컴포넌트를 따로 구현해 빼놓고, 헤더에는 로그아웃 함수만을 전달해 로그아웃 기능을 수행시켰다.
포켓베이스의 authStore와 세션스토리지에서 인증 정보를 지우고, 로그인 상태값을 false로 변경하고 구현 끝!
이 부분은 DB 설계를 조금....?? 잘못 해서 앞으로도 좀 고난의 길이 예상되는 부분인데, 그래도 어떻게 해내긴 했다.
사실 이 부분에서 먼저 했어야 하는 내용이 채팅방 생성 로직인데.. 이 부분은 다음 포스트에서 다루려고 한다. 데이터베이스에 임의로 데이터를 집어넣고 기능을 구현했다.
포켓베이스에서 채팅방 데이터를 가져오고 그것에 맞게 렌더링해주었다.
/* useChatUpdate.js */
function useChatUpdate(userId, setUserName, setChatList) {
useEffect(() => {
useSetInfo(userId, setUserName);
fetchChatRoom(userId).then((data) => {
setChatList([...data]);
});
setSubscribeChat(userId, setChatList);
}, []);
}
/* ChatRoomList.jsx */
function ChatRoomList({ userInfo, changeState }) {
const { id: userId } = useJWTToken(userInfo);
const [userName, setUserName] = useState('');
const [chatList, setChatList] = useState([]);
useChatUpdate(userId, setUserName, setChatList);
return (
<>
<Header userName={userName} handleLogout={handleLogout} />
<section className="p-3 size-full flex flex-col gap-3 overflow-y-scroll scrollbar-hide">
<h3 className="sr-only">채팅방 리스트</h3>
{chatList.length > 0 ? (
chatList.map((item) => {
return (
<ChatRoomCard
key={item.id}
item={item}
me={userId}
opener={handleOpenChatRoom(item.id)}
/>
);
})
) : (
<span className="grid place-items-center h-4/5">
대화중인 상대가 없습니다
</span>
)}
</section>
</>
);
}
사실 useChatUpdate.js에는 부가로 사용하는 함수가 몇 개 더 있는데, 포스트 길이가 좀 길어질까봐..
1. useSetInfo는 헤더에 로그인 정보를 표시해주기 위한 상태 변화 메소드이다. 접속중인 id를 통해 포켓베이스에서 유저 닉네임을 가져온다.
2. fetchChatRoom은 로그인 사용자의 채팅 정보를 가져오는 메소드이다. 마찬가지로 접속중인 id를 통해 포켓베이스에서 채팅 정보를 가져온다.
3. setSubscribeChat은 실시간 채팅 구현을 위해 미리 작성해둔 메소드이다. 포켓베이스에서 제공하는 subscribe 기능을 통해 데이터가 업데이트 되면 콜백함수를 실행시킬 수 있는데, 이 콜백함수에 fetchChatRoom을 지정해주니, 데이터가 업데이트 되면 채팅방 리스트의 마지막 채팅 내용을 업데이트 해준다.
이 기능은 따로 제거하기 전까지 계속 구독하게 되므로, 로그아웃할 때 unsubscribe를 통해 구독을 해지해주는 기능을 추가해놓았다.
슬슬 컴포넌트의 상태와 데이터베이스 설계를 대충 하고 시작한 효과가 나오기 시작하는 부분이었다. 상태를 객체나 배열 등 바꿔가며 이리저리 구현 방법을 고민했는데,
포켓베이스에서 받아오는 데이터가 이상하다 보니 상태를 바꾸면 데이터 구조도 바꿔야 하는 총체적 난국에 빠져있었다.
그 와중 생각해 낸 것이 자바스크립트의 함수 동작 방식으로, 클로저를 이용해 클릭한 채팅방의 ID를 클로저 리턴 함수에 전달하는 방식으로 식별자를 넘기고 구현에 성공했다.
쓰고보니 꼴랑 3문장이지만 일요일 아침10시부터 지금 글쓰기 직전인 오후5시까지 대부분의 고민을 여기에다 쏟았다.. 
그런데 여기까지 한게 어디인가.. 이제 남은 기능은 채팅(핵심인데이제고민해야됨ㅋㅋ), 채팅방 생성 정도가 될 것 같은데 오늘 새벽쯤이면 채팅까지는 완료될 것 같다!!
컨텍스트 API나 라우팅을 배우지 않아서 배운 내용으로만 만들고 있는데, 하다가 찾아보니 배웠으면 분명히 써먹었을 만한 곳이 곳곳에 있었다. 채팅방 식별이라던가.. 컨텍스트 API를 통한 상태 전달이라던가... 이게 바로 Drilling 지옥..?
배포 사이트: https://sangmessenger.netlify.app/
깃허브: https://github.com/SWLee2973/react-homework-4