공통모달창을 만들고 나는 ios환경 다른개발자분이 안드로이드환경에서 테스트를 했는데 안드로이드 뒤로가기 버튼을 눌렀을때 모달창만 꺼지는게 아니라 페이지 자체가 이동한다는 버그를 말씀해주셨다.
뒤로 가기 버튼이요...??
참고로 필자는 ios만 사용하고 있기 때문에 안드로이드 버튼들의 존재자체를 몰랐었다.
그리고 ios에서 뒤로가기 위해서는 앱내에 버튼을 눌러서 이동해야했기 때문에 생각치도 못했었다. (이렇게 또 배워갑니다...)
페이지 이동시 뒤로가기 버튼 터치시 정상동작
모달창을 띄우고 뒤로가기 버튼 터치시 이상하게 동작
둘의 차이점이 뭔가 하니 모달창은 display속성을 바꿔주는거라 페이지이동이라 할 수 없다. 따라서 이 문제를 해결하기 위해서는 모달창을 띄움과 동시에 페이지 이동을 하는것 처럼 동작을 해야한다는 것이다. 그래야 안드로이드 환경에서 뒤로가기 버튼을 눌렀을때 모달창만 닫히는 기능을 구현할 수 있다.
리액트는 SPA방식을 이용하고 있기 때문에 리액트를 사용하고 있는 많은 개발자들이 페이지 이동을 위해 react-router-dom이라는 패키지를 다운받아 사용하고 있는데 react-router-dom 내부에서는 페이지를 이동할때 스택을 사용해서 페이지 이동시 마다 스택을 쌓고 뒤로갈수 있도록 하게한다.
그리고 그 기능을 구현하기 위해 브라우저 내장함수인 Browser history api를 사용하고 있는데 나도 그 api를 사용해서 문제를 해결해 보려 한다.
해야 될것
- 모달창을 열때 새로운 history stack 쌓아주기
- 모달창 닫기 버튼이 아닌 뒤로가기 버튼이 눌렸을때의 이벤트 감지 후 모달창 닫기
window.history.pushState(null, "", window.location.href);
history.pushState(state, title[, url]);
v5까지 있었던 history객체가 v6로 업그레이드 되면서 사라졌다. (하...ㅠ)
따라서 history package를 설치하여 직접 구현하기로 햇다.
npm i history
// modal.js
useEffect(() => {
const event = history.listen((listener) => {
if (listener.action === "POP") {
history.back();
toggleModal();
}
});
return event;
}, [history]);
구글링을 하다보면 onpopstate 함수를 통해 스택을 pop해주는 방식도 있다.
물론 그것을 사용해서 기능을 구현해도 되지만 나같은 경우 두가지 경우
1. 모달창 닫기 버튼을 눌렀을때
2. 뒤로가기 버튼을 눌렀을때
를 고려해야 했는데 window.onpopstate를 사용하면 두가지 경우를 한군데에서 모두 처리해야했다.
history객체를 사용했을때는 두가지 별개로 처리가 가능해서 구현상 쉽게 그리고 버그가 생기지 않을것 같아서 사용하였다.