shallow dive into react-router-dom v6 - createBrowserHistory

박소정·2022년 11월 14일
1
post-thumbnail

어떻게 하면 브라우저 뒤로가기 버튼 클릭 동작을 막을 수 있을까?

최근 과제를 수행하다가 내가 만든 버튼에서의 클릭 이벤트로는 발생할 수 있는 경우의 수를 생각해 에러들을 방지해 두었는데, 브라우저 자체의 뒤로가기, 앞으로가기 경우를 대비하지 않은 것을 발견했다. 게다가 새로고침이 일어나지 않으니 프로젝트에도 치명적인 에러였기 때문에 이 뒤로가기와 앞으로가기 버튼으로 제어할 수 있는 방법을 찾아야했다.

검색을 하다보니 history 를 사용한 예제가 많이 나왔는데 내가 사용하는 react-router-dom은 v6버전이었기 때문에 예제의 내용을 사용할 수 없었고, UNSAFE_NavigationContext라는 함수?를 알게 되었는데 앞에 붙은 UNSAFE가 너무,,,, 쓰고 싶지 않게 생겼다.

unsafe에 대해서 찾아보니

Here, “unsafe” refers not to security but instead conveys that code using these lifecycles will be more likely to have bugs in future versions of React, especially once async rendering is enabled.

라고 공식문서에 설명되어 있어서 비동기 렌더링을 하진 않지만 버그 발생 가능성이 높다니까 일단 패스!

그러다가 unstable_HistoryRouter 도 만났다.

unstable_ 은 무슨 react-router 요청인지에 따라 history의 버전이 맞지 않음으로써 버그를 만날 수 있다는 것을 알려주는 프리픽스라고 한다. 아직 버전에 대한 보호나 경고를 해두지 않은 상태라서 unstable을 붙였다고 하는 이슈의 설명을 보았다.

이슈를 돌아다니다 보니까

contributor분의 설명을 보게 되었는데 이 설명을 보고나니 router와 navigate 그리고 history의 관계에 대해 좀 이해가 되었다!

createBrowserHistory 로 하는 방법도 찾아보았는데 이 부분은 다른 곳에서 import되었다… remix-run…?처음 들어봤다… 근데 뭔가 @로 시작하는걸 보니 @types 같은 그런건가…. 라고 생각했는데 바보였다… react-router-dom을 만든 곳이었다! 이 멍청쓰

createBrowserHistory를 찾아보면 history라는걸 새로 설치해서 사용하길래 @remix-run/router이랑 다른건가 싶었는데 여기 블로그 글을 읽어보니 History나 React Router에서 사용되는 기능들과 같은 기능들이 합쳐질 새로운 패키지들이라고 적혀있길래 안심하고 사용해도 될 것 같아 createBrowserHistory를 사용하기로 하였다!

이 페이지에만 사용할 것이었기 때문에 같은 파일 안에서

const history = createBrowserHistory();

를 만들고 바로 아래에 사진처럼 코드를 작성하였다.

@remix-run/router에서 import한 createBrowserHistory를 써보았는데.............. 동작이 되지 않았다! 에러도 안뜸! 콘솔에 찍어보니

in은 다른거..
"back"이랑 history는 찍히지만 "listen"이랑 history.action은 찍히지 않았다,,
그래서 다시 react-router의 레포에서 이슈를 뒤져보고자 들어갔는데,,,,,,,,

맨 밑의 이슈가 젤 먼저 눈에 들어왔다 ㅎ
https://github.com/remix-run/react-router/issues/9385
쥬르륵

이슈를 작성한 분이 완전히 나와 같은 문제로 보였고, history를 설치해 해결하신걸로 보였고, 나도 결국,,, history 패키지를 설치하기로 했다.

history 패키지를 설치해서 바꾸었는데,,, 안되었다!!!! 왜 안되나 싶어서 뒤로가기를 막막 눌렀더니 드디어 컨펌창이 떴는데, 뭔가 콘솔에 찍힌 만큼 history가 쌓여서 그걸 다 뒤로가기를 해야지만 컨펌창이 뜨는 느낌....? useEffect에 cleanup 함수로 이벤트를 해제도 해주었는데,,, 그러다 내가 본 예제에서는 다들 createBrowserHistory를 따로 만들어서 export해서 사용하고 있던 것이 생각났다!
공식문서를 다시 보니create your own history instance or just import the browser history singleton instance라고 basic usage에 명시되어 있었고, 그렇게 분리해서 작성해 보았더니...!

history.js

import { createBrowserHistory } from "history";

const history = createBrowserHistory();
export default history;
  useEffect(() => {
    const listenBackEvent = () => {
      if (
        window.confirm(
          "페이지를 벗어나면 사진이 사라집니다. 정말 페이지를 나가시겠습니까?"
        )
      ) {
        photoHandler.reshootingHandler();
        photoHandler.countResetHandler();
      } else {
        navigate("/shoot");
      }
    };
    const historyEvent = history.listen(({ action }) => {
      if (action === "POP") {
        listenBackEvent();
      }
    });
    return historyEvent;
  }, []);

이렇게 분리해서 작성하였더니 동작했다!!!!!

그러고 자고 일어났더니 contributor가 새로운 코멘트를 남기며 내가 보고있던 이슈가 닫혔길래 읽어보았더니 초반에 고려했던 unstable_HistoryRouter와 관련해서 라우팅이 일어나기 전에 데이터를 가져오는 함수를 업데이트 하였지만 아직까지는 불안정한 상황이라는 코멘트였다! 다행히 내가 구현하고자했던 부분이랑은 조금 다른 부분이라 일단은 이렇게 구현하고 계속해서 찾아보아야 겠다!

또 다른 에러는,, 페이지를 정말 나가시겠습니까? 컨펌에서 취소를 누르면 return;을 시켜 함수를 종료하고 페이지에 남아있게 하고싶었는데, 아래의 사진을 지우는 함수는 실행되지 않았지만 페이지가 뒤로 가기는 해서 일단 navigate로 막아두었다...ㅎ

그리고 새로고침이 되는 것도 막고 싶었는데 새로고침과 관련해서는 window 객체를 사용해야했다. react스러운 코드를 짜고싶어 window 객체를 쓰지 않는 방향으로 하려고 history 라이브러리를 사용하였는데 이렇게 새로고침에서 window 객체를 사용해야한다면,,,, 다 바꾸는 것이 좋으려나 하는 생각이 들었는데 react-beforeunload라는 패키지를 또 발견함..... 이거 한번 써보겠어.... 간단한 프로젝트인데 뭘 너무 많이 붙이는것 같긴하다...

근데 정말 간단했다!

이렇게 Beforeunload로 감싸주면 새로고침을 할때 알림창이 뜨게 되었다! 근데 크롬에서는 크롬의 기본 문구로 나오고 내 문구는 나오지 않았다...

패키지의 리드미를 읽어보니

흡 그렇다고 한다..!

참고 : https://devnm.tistory.com/9
https://remix.run/blog/remixing-react-router
https://github.com/remix-run/react-router/issues/8264

0개의 댓글