history API(PopState)

이준구·2024년 6월 27일
0

project

목록 보기
2/2

저번 글에 이어, PopState를 해결하는 과정에 대해 이야기할 생각이다.
만약, 이전 과정을 보지 못하신 분은 아래의 링크를 통해 보고 오시면, 더 이해하기 쉽습니당~

👇🏻👇🏻👇🏻
https://velog.io/@leejungoo1396/history-API


해결방법 순서 3)

  • history.pushState(null, "", "") 위치: Main, Room 두 페이지로 변경 및 추가
  • 방나가기 로직: 뒤로가기, 방나가기 버튼을 각각 다르게 처리
  • history stack 관리

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 목록 및 현재 내 위치

    • 1-1)
    • 1-2)

  • 방 나가기 클릭 시 history 목록 및 현재 내 위치

    • 2-1)
    • 2-2)

문제:

  • MainPage에서 리-렌더링 발생 시마다 history.pushState(null, "", "")가 작동되어 history 관리가 어렵다.
  • MainPage에서 특정 page로 이동 후 뒤로가기 클릭 시 컴포넌트 변경 없이 URL만 변경되는 현상이 발생된다.
  • 뒤로가기 및 방 나갈 시 history 기록의 가장 앞으로 이동하기에 특정 웹 브라우저 화면으로 이동된다.



해결방법 순서 4)

해석: 기존 room의 히스토리 기록을 main으로 덮어쓰려 했지만, room의 히스토리 기록은 유지하면서 실제로는 다시 접근하지 못하도록 변경

  • history.pushState(null, "", "") 위치: Room 페이지로 변경
  • 방나가기 로직: router.replace("/main") 변경
  • 조건부 렌더링을 통해 방입장, 방나가기 구분, 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 목록 및 현재 내 위치

📚📚 참고 문서)

profile
개발 중~~~ 내 자신도 발전 중😂🤣

0개의 댓글

관련 채용 정보