저번 글에 이어, PopState를 해결하는 과정에 대해 이야기할 생각이다.
만약, 이전 과정을 보지 못하신 분은 아래의 링크를 통해 보고 오시면, 더 이해하기 쉽습니당~
1) history.pushState(null, "", "") 위치: Main, Room 두 페이지로 변경 및 추가
const Mainpage = () => {
useEffect(() => {
// Main history 추가
history.pushState(null, "", "");
// history stack 관리
if (history.length >= 5) {
const back = (history.length - 1) * -1;
history.go(back);
history.pushState(null, "", "");
}
}, []);
}
const JoinMafiaRoom = () => {
//room history 추가
useEffect(() => {
history.pushState(null, "", "");
// popState Event
const handlePopstate = (e: PopStateEvent) => {
socket.emit("exitRoom", roomId, userId);
setIsExit(true);
};
// 이벤트 리스너 등록
window.addEventListener("popstate", handlePopstate);
// 이벤트 리스너 제거
return () => window.removeEventListener("popstate", handlePopstate);
}, []);
}
2) 방나가기 로직: 뒤로가기, 방나가기 버튼을 각각 다르게 처리
const Loading = () => {
const router = useRouter();
const { setIsExit } = useExitStore();
useEffect(() => {
//router.replace("main");
//뒤로가기
if (isBack) {
const back = (history.length - 2) * -1;
history.go(back);
}
// 방나가기
const back = (history.length - 1) * -1;
history.go(back);
return () => {
setIsExit(false);
};
}, []);
return (
<section className={`${S.loadingWrapper} ${designer.className}`}>
<div>IceCraft</div>
<div>Loading...</div>
<div>메인페이지로 이동중 입니다.</div>
</section>
);
};
export default Loading;
뒤로 가기 시 history 목록 및 현재 내 위치
방 나가기 클릭 시 history 목록 및 현재 내 위치
문제:
- MainPage에서 리-렌더링 발생 시마다
history.pushState(null, "", "")
가 작동되어 history 관리가 어렵다.- MainPage에서 특정 page로 이동 후 뒤로가기 클릭 시 컴포넌트 변경 없이 URL만 변경되는 현상이 발생된다.
- 뒤로가기 및 방 나갈 시 history 기록의 가장 앞으로 이동하기에 특정 웹 브라우저 화면으로 이동된다.
해석: 기존 room의 히스토리 기록을 main으로 덮어쓰려 했지만, room의 히스토리 기록은 유지하면서 실제로는 다시 접근하지 못하도록 변경
방입장, 방나가기 구분
, URL 직접 접근, 뒤로가기 접근 방지
const RoomPage = () => {
const isEntry = useIsEntry();
return <>{isEntry ? <JoinMafiaRoom /> : <Loading />}</>;
};
const JoinMafiaRoom = () => {
const roomId = useParams();
const { setIsEntry } = useRoomAction();
const isPopState = usePopStateHandler();
//NOTE - 뒤로가기 시 작동
useEffect(() => {
if (isPopState) {
socket.emit("exitRoom", roomId.id, userInfo.userId);
setIsEntry(false);
}
}, [isPopState]);
...
const usePopStateHandler = () => {
const [isBack, setIsBack] = useState(false);
useEffect(() => {
//현재 페이지의 history 추가
history.pushState(null, "", "");
const handlePopstate = (e: PopStateEvent) => {
setIsBack(true);
};
window.addEventListener("popstate", handlePopstate);
return () => window.removeEventListener("popstate", handlePopstate);
}, []);
return isBack;
};
export default usePopStateHandler;
const Loading = () => {
const router = useRouter();
useEffect(() => {
const timer = setTimeout(() => {
router.replace("/main");
}, 3000);
return () => clearTimeout(timer);
}, []);
return (
<section className={`${S.loadingWrapper} ${designer.className}`}>
<div>IceCraft</div>
<div>Loading...</div>
<div>메인페이지로 이동중 입니다.</div>
</section>
);
};
export default Loading;
방 입장 시 history 목록 및 현재 내 위치
뒤로 가기 시 history 목록 및 현재 내 위치
앞으로 가기 및 URL 직접 접근으로 재접속시 history 목록 및 현재 내 위치
📚📚 참고 문서)