안녕하세요! 라미팀의 Front-End Lead 문대승이에요!
오늘은 저희 라미챗에서 새롭게 시도한 재미있는 UX 개선 이야기를 들려드릴게요.
웹 개발자라면 한 번쯤 고민해봤을 법한 그 문제, 바로 '모바일 메뉴'에 관한 이야기에요!
"모바일에서 전체 화면 메뉴가 열렸을 때, 사용자들은 자연스럽게 브라우저 뒤로가기를 누르려고 해요."
어느 날 기획팀에서 받은 이런 피드백 하나로, 저희는 재미있는 도전을 시작하게 되었어요.
자, 이제 저희가 어떻게 이 문제를 해결했는지, 그 과정에서 배운 점들을 하나씩 소개해드릴게요!
UX 개선의 시작: 사용자의 작은 불편함에서 시작된 도전
기획팀의 흥미로운 발견
"사용자들이 모바일 메뉴를 전체 화면으로 열었다가 닫을 때, 대부분 뒤로가기를 누르더라고요!"
처음 이 피드백을 들었을 때, "아, 그러고 보니 나도 그렇게 하려고 했었네?" 하는 생각이 들었어요. 모바일에서 전체 화면을 차지하는 UI는 사용자들에게 마치 새로운 페이지처럼 인식되는 경향이 있거든요. 그래서 자연스럽게 뒤로가기를 누르게 되는 거죠.
기존 방식의 한계
기존에는 모바일 메뉴를 그저 평범한 모달처럼 다뤘어요.
const [isOpen, setIsOpen] = useState(false);
JavaScript
복사
이렇게 단순한 상태값으로 관리했죠. 간단하지만... 뭔가 아쉬웠어요.
사용자들은 이미 브라우저의 뒤로가기를 통한 네비게이션에 익숙해져 있는데, 우리 메뉴는 그렇지 못했거든요.
그래서 생각했습니다
"잠깐, 이거 History API로 해결할 수 있지 않을까?"
브라우저의 history를 활용하면, 사용자들이 기대하는 그대로의 동작을 구현할 수 있을 것 같았어요. 게다가 URL을 통한 상태 관리라니, 이거 꽤 멋진 해결방법이 될 것 같았습니다!
다음 섹션에서는 제가 어떻게 History API를 활용해서 이 문제를 해결했는지 자세히 설명해드릴게요.
브라우저 History로 자연스러운 UX 만들기
"잠깐, 전체 화면 메뉴라면 이걸 하나의 화면처럼 다뤄볼 수 있지 않을까?"
이런 생각에서 시작된 아이디어였어요. 모바일 메뉴가 열릴 때마다 브라우저의 history에 새로운 상태를 추가하면 어떨까요? 마치 새로운 페이지로 이동한 것처럼요!
브라우저 History API의 재발견
const [{ isMenuOpen }, setParams] = useQueryParams({
isMenuOpen: 'boolean'
});
JavaScript
복사
이렇게 하면 정말 신기한 일이 일어납니다:
•
메뉴가 열리면 URL에 상태가 기록되고
•
사용자가 뒤로가기를 누르면 자연스럽게 메뉴가 닫히고
•
앞으로가기를 누르면 다시 메뉴가 열리죠!
이게 바로 네이티브 앱같은 경험을 웹에서 구현하는 방법이었습니다.
사용자의 기대를 충족시키는 UX
브라우저의 네비게이션은 이미 사용자들에게 익숙한 패턴이에요. 우리는 그저 이 익숙한 패턴을 모바일 메뉴에 적용한 것뿐이죠.
다음 섹션에서는 이 구현의 세부적인 최적화 방법을 소개해드릴게요!
구현 세부사항: 성능까지 생각한 꼼꼼한 설계
메뉴가 열리고 닫힐 때마다 UI가 깜빡이면 안 되겠죠? TypeScript와 React의 힘을 빌려 최적화된 구현을 만들어보았어요.
선택적 렌더링으로 성능 최적화
// 메뉴 컴포넌트
const MobileMenu = () => {
const [{ isMenuOpen }, setParams] = useQueryParams({
isMenuOpen: 'boolean' // 타입 지정으로 안전하게!
});
const handleClose = useCallback(() => {
setParams({ isMenuOpen: false });
}, []);
return isMenuOpen ? (
<div className="mobile-menu">
{/* 메뉴 내용 */}
</div>
) : null;
};
TypeScript
복사
여기서 포인트는:
•
isMenuOpen 상태가 변할 때만 리렌더링 발생
•
다른 URL 파라미터가 변해도 이 컴포넌트는 영향 받지 않아요
•
TypeScript로 타입 안전성 확보
History API와의 우아한 연동
// URL 상태 변경을 처리하는 부분
useEffect(() => {
const handleStateChange = () => {
// URL 변경 감지 시 메뉴 상태 업데이트
};
window.addEventListener('popstate', handleStateChange);
return () => window.removeEventListener('popstate', handleStateChange);
}, []);
TypeScript
복사
브라우저의 네비게이션 이벤트를 놓치지 않고 캐치해서, 자연스러운 UX를 만들어냅니다.
이렇게 구현하니 정말 네이티브 앱처럼 동작하는 웹 경험을 만들 수 있었어요!
다음 섹션에서는 이 개선된 UX가 가져온 실제 효과를 공유해드릴게요.
작은 변화가 가져온 큰 개선
이렇게 브라우저의 History API를 활용한 모바일 메뉴 개선이 완료되었습니다!
처음에는 단순해 보였던 기획팀의 요청이 이렇게 흥미로운 기술적 도전이 되었네요.
개선된 점들
•
사용자들이 기대하는 대로 뒤로가기로 메뉴가 닫힘
•
불필요한 상태 관리 라이브러리 도입 없이 깔끔한 구현
•
TypeScript의 도움으로 안전하고 견고한 코드베이스
•
선택적 렌더링으로 성능까지 챙김
배운 점
가끔은 새로운 라이브러리나 복잡한 솔루션 대신, 브라우저가 제공하는 기본 기능을 잘 활용하는 것만으로도 훌륭한 UX를 만들 수 있다는 걸 다시 한 번 깨달았습니다.
기획팀의 작은 피드백이 이렇게 멋진 기술적 발전으로 이어질 수 있다니, 역시 개발은 재미있네요!
다음은?
이번 경험을 바탕으로 다른 UI 요소들도 브라우저의 기능을 적극 활용하는 방향으로 개선해볼 생각입니다. 여러분의 프로젝트에서도 이런 시도를 해보시는 건 어떨까요?
코드가 궁금하신가요? 여러분을 위해 특별히 공개해드릴게요!
use-query-params.ts
#프론트엔드개발 #React #TypeScript #UX #WebDevelopment