#Frontend

항공 프론트엔드 구축기 (5/10): 뒤로가기가 가장 어려웠다

항공 프론트엔드 구축기 (5/10): 뒤로가기가 가장 어려웠다
01

Summary

웹과 앱의 뒤로가기를 코드 하나로 해결하는 똑똑한 모달 제어법

브라우저 히스토리와 하드웨어 백키의 극적인 타협점을 찾아서

웹의 히스토리 기반 뒤로가기와 웹뷰의 하드웨어 백키는 동작 원리가 근본적으로 다릅니다. 이 아티클은 두 환경의 고유 방식을 억지로 통합하지 않고, 공통 콜백으로 수렴시키는 추상화 구조를 설계하여 뒤로가기 문제를 깔끔하게 해결한 여정을 공유합니다. 덕분에 개발자들은 웹인지 앱인지 의식하지 않고 직관적인 컴포넌트 선언만으로 완벽한 네비게이션을 구현하게 되었습니다.

  • 01웹뷰 환경에서는 DOM 마운트 순서를 활용한 보이지 않는 트리거 버튼 구조로 전역 백키 이벤트를 안전하게 수신
  • 02웹 환경에서는 URL 해시(#modal)와 popstate를 단일 싱글톤 매니저가 전담하여 모달 상태를 조율하도록 개선
  • 03뒤로가기 시 닫혀야 하는 모달과 사용자 입력을 대기하기 위해 버텨야 하는 모달의 타입을 분리하여 안정성 강화
  • 04서비스 개발 코드에서는 백키 제어 코드가 단 한 줄도 남지 않도록 완벽한 캡슐화 달성

RECOMMENDATION

웹과 웹뷰를 동시에 지원하는 하이브리드 앱 환경의 프론트엔드 엔지니어에게 적극 추천합니다. 특히 모달, 바텀시트 등의 복잡한 네비게이션 스택 처리에 골머리를 앓고 있다면 아티클의 이원화된 콜백 매핑 아키텍처가 실무적인 돌파구가 될 것입니다.

The Problem

웹 브라우저의 히스토리 방식과 안드로이드 하드웨어 백키 방식이 서로 달라, 하나의 프론트엔드 코드베이스에서 두 환경의 뒤로가기 동작을 일관되게 제어하기 어려웠습니다. 특히 단순 라우터 백을 실행하면 화면 전체가 뒤로 이동하여 떠 있는 모달이나 다이얼로그만 순차적으로 닫지 못하는 문제가 발생했습니다.

The Solution

웹과 웹뷰 환경의 메커니즘을 억지로 하나로 합치지 않고, 동일한 콜백에 도달하도록 추상화했습니다. 웹뷰에서는 마운트 순서대로 data-order를 가진 보이지 않는 버튼을 렌더링하여 전역 백키 핸들러가 가장 최근의 버튼을 클릭하게 했고, 웹에서는 단일 싱글톤 매니저가 URL 해시(#modal)와 popstate 리스너를 소유하여 모달의 등록 및 히스토리 이벤트를 조율하도록 구현했습니다.

The Result

서비스 레이어의 개발 코드는 백키 처리 로직을 완전히 배제하고 오직 onHide와 onNativeBack 속성만 정의하도록 완전히 추상화되었습니다. 이를 통해 웹과 웹뷰 양쪽 환경 모두에서 복잡한 뒤로가기 분기문 없이도 안전하고 자연스러운 사용자 경험을 제공할 수 있게 되었습니다.

Trade-off

웹 환경에서 겹쳐 있는 모달들이 뒤로가기 한 번에 모두 닫히는 한계가 존재합니다. 또한 뒤로가기를 흡수하는 로직의 오작동을 방지하기 위해 100ms 타임아웃 같은 경험적 수치에 의존하는 트릭이나 화면 딤드 영역을 2배로 넓게 그리는 임시방편적 트릭을 일부 사용했습니다.

03

Key Concepts

Concept · 01

하드웨어 백키 제어권 위임

네이티브 앱의 물리적인 백키 동작 처리를 앱 내부에서 처리하지 않고, 브릿지를 통해 웹뷰(Javascript) 영역으로 위임하여 웹 애플리케이션이 직접 뒤로가기 동작을 제어하도록 하는 방식입니다.

  • 앱의 handleBackKey 전역 함수가 호출되면 웹에 렌더링된 트리거 컴포넌트들이 이를 가로채 동작을 제어함
  • 이를 활성화하기 위해 화면 진입 시 appBridge.enableWebBackHandling()을 실행함
Concept · 02

NativeBackTrigger

웹뷰 환경에서 전역 백키 이벤트가 전달되었을 때, React 상태 밖의 DOM 마운트 순서를 활용하여 가장 위에 떠 있는 모달을 판별하고 물리적인 클릭 이벤트를 시뮬레이션하는 화면에 보이지 않는 컴포넌트입니다.

  • 마운트될 때 고유한 data-order 값을 할당받아 스택의 우선순위를 결정함
  • React 트리 바깥의 네이티브 진입점에서 document.querySelectorAll을 통해 타겟 엘리먼트를 손쉽게 탐색함
Concept · 03

히스토리 매니저 싱글톤

브라우저의 URL 해시(#modal) 및 popstate 리스너의 소유권을 컴포넌트 개별이 아닌 단일 객체로 집중화하여, 여러 모달 간의 히스토리 동기화 어긋남(Desync)을 방지하는 디자인 패턴입니다.

  • 첫 모달이 열릴 때만 #modal을 푸시하고, 마지막 모달이 닫힐 때에만 뒤로가기(back)를 조율함
  • 모달이 빠르게 닫히고 열릴 때 생기는 불필요한 히스토리 변경을 예약을 취소하는 방식으로 보완함