리액트 뒤로가기 이벤트 감지 - liaegteu dwilogagi ibenteu gamji

만약에 A 컴포넌트에 name 상태값이 있다고 가정하자

사용자가 A 컴포넌트의 name 상태값을 수정하였으나 실수로 브라우저 뒤로가기를 누르면 A 컴포넌트는 언마운트되고 수정했던 name 상태값은 유실된다.

 

이런 경우를 방지하기 위해 브라우저 뒤로가기 발생 시 '정말 뒤로 가겠습니까?'와 같이 사용자에게 한 번 더 확인을 요구하는 confirm 창을 띄울 수 있다.

 

리액트 뒤로가기 이벤트 감지 - liaegteu dwilogagi ibenteu gamji

 

history에서는 block으로 push/pop을 제어하여 이를 처리할 수 있도록 한다.

다음은 상태값이 변경되어 isBlocking이 true, action이 'POP'일 때 confirm창을 띄우는 예시이다.

리액트 뒤로가기 이벤트 감지 - liaegteu dwilogagi ibenteu gamji
코드 예시

참고

React Router v5.2 - Blocking route change with createBrowserHistory and history.block

(React) react-router history.block 적용해보기 - Prevents navigation

공유하기

게시글 관리

구독하기요즘 개발

'Today I Learn > 이슈 해결' 카테고리의 다른 글

[Nextjs] 리액트에서 Nextjs로 이전하던 중 생긴 이슈들  (0)2021.07.28[React] render() 내에서 history.push(replace)를 하면 안되는 이유  (0)2021.07.08getEventListeners로 등록된 이벤트리스너 확인하기  (0)2021.06.14[JS] Blur 이벤트 전에 Click 이벤트를 실행하기  (0)2021.03.17react-router-dom __RouterContext 미존재 이슈  (0)2021.01.21

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() 메서

선생님 안녕하세요
웹에서 뒤로가기 시에 이벤트 감지해서 나갈꺼냐고 물어보고 싶은데 방법이 있을까요?
구글링해서 아래와 같이 했는데 다른 환경(안드로이드,데스크탑 등)에서는 작동을 하는데 아이폰 사파리에서는 안먹혀서.. 헤매고 있습니다. 도와주세요 ㅠㅠ
  useEffect(() => {
    const preventGoBack = () => {
      if (confirm('페이지를 나가시겠습니까?')) {
        history.go(-1);
      } else {
        history.pushState(null, '', location.href);
      }
    };
    history.pushState(null, '', location.href);
    window.addEventListener('popstate', preventGoBack);
    return () => window.removeEventListener('popstate', preventGoBack);
  }, []);
  • 이 게시글은 에 의해 3 months 전에 수정됐습니다.

React router v5에서는 useHistory 의 return value인 historyhistory.listen() 으로 뒤로가기 이벤트를 탐지하는 예제가 많이 나온다. 그러나 최근에 React router가 v6 업데이트 되면서 useHistory가 없어지며 history.listen을 사용하시던 분들과 뒤로가기 이벤트 탐지를 검색하시던 분들이 어려움을 겪었을 것이다. 필자 또한 이 방법을 찾느라 + 그냥 코드를 잘못 적었는데 몰라서 뒤로가기 이벤트 탐지 기능을 구현하는 데 애를 먹었다.

history.ts

import { createBrowserHistory } from "history";

export const history = createBrowserHistory();

먼저 react-router에 history가 없어졌으니 history 라이브러리에서 가져오자. 패키지 매니저에 따라 yarn add history

import { history } from "some/directory/history"

useEffect(() => {
    const listenBackEvent = () => {
      // 뒤로가기 할 때 수행할 동작을 적는다
    };

    const unlistenHistoryEvent = history.listen(({ action }) => {
      if (action === "POP") {
        listenBackEvent();
      }
    });

    return unlistenHistoryEvent;
  }, [
  // effect에서 사용하는 state를 추가
]);
0로 추가하면 된다.
추가했으면
import { history } from "some/directory/history"

useEffect(() => {
    const listenBackEvent = () => {
      // 뒤로가기 할 때 수행할 동작을 적는다
    };

    const unlistenHistoryEvent = history.listen(({ action }) => {
      if (action === "POP") {
        listenBackEvent();
      }
    });

    return unlistenHistoryEvent;
  }, [
  // effect에서 사용하는 state를 추가
]);
1로 history 객체를 생성한다

page.tsx

import { history } from "some/directory/history"

useEffect(() => {
    const listenBackEvent = () => {
      // 뒤로가기 할 때 수행할 동작을 적는다
    };

    const unlistenHistoryEvent = history.listen(({ action }) => {
      if (action === "POP") {
        listenBackEvent();
      }
    });

    return unlistenHistoryEvent;
  }, [
  // effect에서 사용하는 state를 추가
]);

그 다음은 아까 만들었던 history객체를 import만 하면 기존에 useHistoryhistory를 사용하는 것과 똑같다. history의 update event를 listen하여 action이

import { history } from "some/directory/history"

useEffect(() => {
    const listenBackEvent = () => {
      // 뒤로가기 할 때 수행할 동작을 적는다
    };

    const unlistenHistoryEvent = history.listen(({ action }) => {
      if (action === "POP") {
        listenBackEvent();
      }
    });

    return unlistenHistoryEvent;
  }, [
  // effect에서 사용하는 state를 추가
]);
5일 때 (뒤로가기. 쌓아온 사용자 history stack을 pop 하는 거라서 뒤로가기다) 원하는 동작을 수행해야 한다.
이 때
import { history } from "some/directory/history"

useEffect(() => {
    const listenBackEvent = () => {
      // 뒤로가기 할 때 수행할 동작을 적는다
    };

    const unlistenHistoryEvent = history.listen(({ action }) => {
      if (action === "POP") {
        listenBackEvent();
      }
    });

    return unlistenHistoryEvent;
  }, [
  // effect에서 사용하는 state를 추가
]);
6으로 건 이벤트를 해제해야 하니 주의해야 한다. 그렇지 않으면 이벤트가
import { history } from "some/directory/history"

useEffect(() => {
    const listenBackEvent = () => {
      // 뒤로가기 할 때 수행할 동작을 적는다
    };

    const unlistenHistoryEvent = history.listen(({ action }) => {
      if (action === "POP") {
        listenBackEvent();
      }
    });

    return unlistenHistoryEvent;
  }, [
  // effect에서 사용하는 state를 추가
]);
7가 실행될 때마다 추가되기만 해서 같은 이벤트 여러개가 동작할 것이다. history.listen을 해제하는 방법은 history.listen이 return하는 함수를 호출하면 된다. 이 함수를 effect cleanup에 넣어서 다른 state를 가진 이벤트가 실행되기 전에 이전 이벤트가 해제되도록 하자.

공유하기

게시글 관리

구독하기Monsters Dev.

저작자표시

'React' 카테고리의 다른 글

useEffect() clean up은 언제 동작할까?  (0)2022.01.17Apollo 캐시값 갱신 - Troubleshooting 기록  (0)2022.01.14React svg 파일 import 하는 방법 - Failed to execute 'createElement' 에러 해결법  (0)2022.01.11Apollo codegen globalTypes.ts 경로 변경하는 법 (Relative imports outside of src/ are not supported 에러)  (0)2022.01.04Troubleshooting 기록 - 회원가입 로직  (0)2022.01.03