
여기어때 개발팀이 한 벌의 코드로 하이브리드 앱과 반응형 웹의 디바이스 경계를 허문 실무 가이드
본 아티클은 모바일 하이브리드 앱과 데스크톱 웹 환경을 단 하나의 프론트엔드 코드베이스로 다루며 마주한 레이아웃 설계와 상태 제어의 한계를 깊이 있게 고찰합니다. 화면 크기, 플랫폼 유형, 포인팅 디바이스 유무라는 독립적인 세 가지 기준을 정립하여 복잡한 분기 비용을 낮추고, SSR 환경의 최대 난제인 초기 렌더링 CLS 문제를 해결하기 위한 구체적인 방법론을 공유합니다.
하이브리드 앱과 반응형 웹 서비스를 동시에 단일 코드베이스로 관리하고 계신 프론트엔드 개발자분들과, SSR 적용 이후 디바이스 감지 및 레이아웃 누수 현상에 대한 안정적인 해결책을 고민하시는 시니어 설계자분들께 적극 추천합니다.
웹과 모바일 앱(웹뷰) 환경에서 플랫폼 형태와 화면 너비를 구별하지 않고 단일 환경 변수로 혼용하여 UI 분기 처리에 한계가 있었으며, SSR(서버 사이드 렌더링) 시 화면 너비를 선제적으로 알지 못해 초기 로딩 단계에서 레이아웃이 흔들리는(CLS) 문제와 디바이스 전환 시 입력 상태가 초기화되는 문제가 발생했습니다.
환경 판단 플래그를 플랫폼 유형, 화면 너비, 입력 장치 사양의 세 가지 독립된 질문으로 세분화하고 React 18의 useSyncExternalStore 훅을 도입해 안정적으로 윈도우 크기를 구독하도록 조치했습니다. 또한 레이아웃 이중 처리(CSS 방식)와 영역 예약(Mounted 방식)을 상황에 맞춰 트레이드오프하고 컴포넌트를 언마운트하지 않은 채 Prop 전달을 통해 렌더링 형태만 제어하도록 설계했습니다.
사용자가 브라우저 창 너비를 임의로 조정하더라도 드롭다운이나 팝업창 등 컴포넌트의 활성화 상태와 사용자 입력값이 온전히 유지되는 향상된 반응형 UX를 구현했으며, 하나의 공통 컴포넌트 코드로 웹과 하이브리드 앱의 다양한 화면 규격을 효율적으로 제어하게 되었습니다.
Trade-off
SSR 환경에서 CLS를 피하기 위해 CSS로 이중 렌더링 시 보이지 않는 DOM의 렌더링 비용이 발생하며, 마운트 지연(자리 예약) 방식을 택할 시 고정 마크업 높이값을 유지보수 단계에서 수동으로 싱크 맞춰야 하는 관리 공수가 따릅니다. 또한 컴포넌트를 유지하는 전제 하에 기존에 바인딩되어 있던 스크롤 핸들러나 DOM 캐시 요소가 오작동하지 않도록 꼼꼼한 라이프사이클 핸들링이 추가로 요구됩니다.
React 18에 탑재된 API로 외부의 데이터 소스나 브라우저의 전역 상태(예: window.innerWidth)를 리액트 생명주기와 동기화하여 안전하게 구독할 수 있게 돕는 훅입니다.
서버가 브라우저 해상도를 모르는 상태에서 렌더링된 초기 HTML이 클라이언트에 도달해 Hydration 될 때 레이아웃 구조가 튕기듯이 변하는 현상을 극복하기 위한 최적화 기법입니다.
디바이스 규격 및 해상도가 실시간으로 전환될 때 상위 구조만 변경하고 내부 컴포넌트를 무조건 재생성(Remount)하지 않아 내부 로컬 상태를 일관성 있게 보전하는 렌더링 설계 전략입니다.




