본문 바로가기

Web.d

[React][Javascript] 뒤로 가기 막기 / 창 닫기 막기 / 새로고침 막기

반응형

서비스의 필요성

북스테어즈(https://book-stairs.com/) 서비스 작업을 하다가

 

진짜 독서가들의 독서법 - 북스테어즈

뇌 과학 기반의 차별화 된 독서법을 제안합니다.

book-stairs.com

뒤로 가기 막기 / 창 닫기 막기 / 새로고침 막기의 기능이 요구되었다

 

우리가 글 작성 등의 작업을 하며

실수로 뒤로 가기, 새로고침, 창 닫기를 한다고 생각해보자

정말 끔찍하다!

 

이에 대해 네이버 블로그같은 경우에는, 아래 사진과 같이 경고창을 띄우며 막는다

 

네이버 블로그 예시

 

우리 서비스에도 독서를 하며 질문과 답변을 직접 작성하는 기능이 주이기 때문에,

위와 같은 기능이 꼭 필요할 것 같다

 

하나씩 해보도록 하자

 


창 닫기 및 새로고침 막기

창이 닫히거나, 새로고침을 할 경우에 window 객체beforeunload 이벤트를 발생시킨다

 

beforeunload 는 문서나 그 리소스가 unload 되기 직전 window에서 발생한다

그리고 이는 Cancelable(취소 가능) 하여

e.preventDefault() 메소드로 창이 닫히거나 새로고침 등을 취소할 수 있다

 

https://developer.mozilla.org/ko/docs/Web/API/Window/beforeunload_event

 

Window: beforeunload 이벤트 - Web API | MDN

beforeunload 이벤트는 문서와 그 리소스가 언로드 되기 직전에 window에서 발생합니다.

developer.mozilla.org

 

공식 문서의 예제에도 나와있듯이,

간단하게 구현이 가능하다

 

window.addEventListener('beforeunload', (event) => {
  // 표준에 따라 기본 동작 방지
  event.preventDefault();
  // Chrome에서는 returnValue 설정이 필요함
  event.returnValue = '';
});

 

그리고 위 코드를 React에 적용을 시키기 위해,

useEffect에 작성하였다

 

const preventClose = (e: BeforeUnloadEvent) => {
  e.preventDefault();
  e.returnValue = ""; //Chrome에서 동작하도록; deprecated
};

useEffect(() => {
  (() => {
    window.addEventListener("beforeunload", preventClose);
  })();

  return () => {
    window.removeEventListener("beforeunload", preventClose);
  };
}, []);

 

이벤트 객체의 returnValue deprecated 된 속성이지만, 일단 넣어줬다

 

https://developer.mozilla.org/en-US/docs/Web/API/Event/returnValue

 

Event.returnValue - Web APIs | MDN

The Event property returnValue indicates whether the default action for this event has been prevented or not.

developer.mozilla.org

 

또한 useEffect에서 위 코드와 같이 콜백함수로 감싸주어야,

보다 더 명확한 동작이 이루어진다고 한다

 

https://ko.reactjs.org/docs/hooks-effect.html

 

Using the Effect Hook – React

A JavaScript library for building user interfaces

ko.reactjs.org

 

같은 방법으로, 뒤로 가기 동작도 막아보도록 하자

 


뒤로 가기 막기

뒤로 가기를 할 때에는 popstate 이벤트가 발생한다

 

이는 사용자가 세션 기록 탐색을 하여, 현재 활성화된 기록 항목이 바뀔 때 발생한다

 

https://developer.mozilla.org/ko/docs/Web/API/Window/popstate_event

 

popstate - Web API | MDN

Window 인터페이스의 popstate 이벤트는 사용자의 세션 기록 탐색으로 인해 현재 활성화된 기록 항목이 바뀔 때 발생합니다. 만약 활성화된 엔트리가 history.pushState() 메서드나 history.replaceState() 메서

developer.mozilla.org

 

popstate 이벤트가 beforeunload 이벤트와 다른 점은 Cancelable 하지 않다는 점이다

이 이유로 e.preventDefault() 메소드로 동작을 막을 수는 없다

 

 

공식 문서에도 언급된, history.pushState(state, title[, url]) 메서드를 활용한다

 

https://developer.mozilla.org/ko/docs/Web/API/History/pushState

 

History.pushState() - Web API | MDN

HTML 문서에서, history.pushState() 메서드는 브라우저의 세션 기록 스택에 상태를 추가합니다.

developer.mozilla.org

 

아래 코드를 보자

 

history.pushState(null, "", location.href);
window.addEventListener("popstate", () => history.pushState(null, "", location.href));​

 

우선, 브라우저의 세션 기록 스택에 상태를 추가한다

이 상태는 현재 페이지의 상태 그대로이므로 복사본을 저장하는 꼴이다

 

그리고 window 객체에 popstate 이벤트 리스터를 추가한다

그 때에도 history.pushState() 메소드를 불러옴으로써 복사본을 저장한다

 

그렇게 되면 우리가 뒤로 가기를 눌러도, 현재 상태를 유지하게 되고, 

하나를 또 복사하였으므로 다음 뒤로 가기도 안 눌리게 된다

 

이를 React에 적용을 시키기 위해,

useEffect에 작성하면 다음과 같다

 

const preventGoBack = () => {
  history.pushState(null, "", location.href);
};

useEffect(() => {
  history.pushState(null, "", location.href);
  window.addEventListener("popstate", preventGoBack);

  return () => {
    window.removeEventListener("popstate", preventGoBack);
    handleCloseDrawer();
  };
}, []);

 


나아갈 점

window 객체의 조작React에 적용하였다

그래서 어떠한 상태(state)에 따라 달리 처리하고 싶었다

 

예를 들어, 글이 변경되어야 뒤로 가기를 막는다던지?

 

그러나 이를 구현할 때 문제였던 점

페이지를 렌더링 하는 시점에서부터 history.pushState() 메소드를 호출한다는 것이다

 

이렇게 되면, 글이 변경되지 않았을 때 뒤로 가기를 2번 눌러서야 뒤로 가기가 동작한다

 

이 부분에 대해서는 조금 더 생각을 해봐야 할 것 같다 🧐🧐

반응형