2024.06.17~21, 5일 동안 진행된 아웃소싱 프로젝트
프로젝트 주요 내용: https://github.com/hyeonseok98/3-feet
상세 페이지를 맡으며
팀원들끼리 기능 역할분담을 하며 상세 페이지를 맡았을 때는 그렇게 어려운 작업 없어 보여서 '금방 끝나겠네'라는 생각을 조금 했었다. 하지만 디테일을 하나 둘 챙기다 보니 결코 작업량이 적지 않았다. 이렇게까지 디테일적인 부분을 많이 챙겨본 것은 처음이지만 확실히 꼼꼼할수록 사용자의 편의성이 크게 향상되는 것 같았다.
디테일 1. 상세페이지를 모달로?
말 그대로 상세 '페이지', 어제자 TIL에 썼듯 지도 api와 숙소/맛집 api를 활용하는 페이지에서 사용자는 여러 숙소나 맛집 정보를 빠르게 확인하고 싶을 텐데 매번 페이지를 이동하게 되면 api를 받아오는 시간 동안 빈 화면을 보게 되 이탈률이 높아질 것 같았다. 때문에 모달로 구현하려 했는데 한 가지 문제점을 마주하게 되었다.
문제점: Modal Context Provider가 router 밖에 위치
상세 페이지 모달은 추후 댓글창을 클릭했을 때 로그인되지 않은 유저라면 로그인 페이지로 이동시키고 다시 해당 상세 페이지로 리다이렉트 하는 기능을 포함하려고 했다. 때문에 URL주소가 필요한데 일반적인 모달에는 주소가 배정되지 않는다..! 그래서 context api로 구현한 모달을 열 때 가게 정보에 따라 동적 id를 줘서 라우팅을 해주려 했으나, 모달이 라우터의 영향 밖에 위치해 동적 라우팅 구현이 불가능하게 되었다.
때문에 순서를 반대로 RouteProvider로 ModalProvider를 감싸는 실험을 했는데, 뭔가 당연하게도 작동하지 않았다. 이 문제에 대해서는 ModalProvider가 초기화될 때 라우터 관련 정보가 준비되지 않아 그렇지 않을까?라고 추측하였다. 그래서 이 문제로 튜터님을 찾아갔는데, 튜터님은 next.js에서 사용되는 '얕은 라우팅' 방법을 추천해 주셨다. 얕은 라우팅은 보통 next.js와 같은 프레임워크에서 페이지를 완전히 새로 로드하지 않고 URL만 변경하여 상태를 업데이트하는 방식이다. 때문에 빠르게 페이지 전환이 가능해지고 상태 유지에도 탁월하다.
이 개념에 대해 처음 들어보았기 때문에 이번엔 튜터님의 도움으로 코드에 구현이 되었는데, useSearchParmas를 이용해 QueryString을 이용해 기본 URL 뒤에 '? + 가게 고유 id'를 붙여 최종적인 주소를 만들어냈다. 모달을 닫을 때는 쿼리 스트링을 빈 객체로 만들어 원래의 주소로 가게 하는 동작 방식을 가지고 있다.
이런 건 처음 보는 방식이라 구현이 되는 것이 마냥 신기했는데, 해당 내용을 좀 더 알아보고 직접 사용해 보아야 완벽히 이해될 것 같아 주말에 좀 더 코드를 작성해 봐야 한다...
디테일 2. 비로그인 유저 기능 제한(댓글) + 중첩 모달
디테일 1에서 상세 페이지 모달에서도 주소값을 부여했으니, 비로그인 유저는 댓글을 입력하려면 먼저 로그인을 하고 올 수 있도록 처리할 수 있었다. 전에 로그인이 필요한 기능의 경우 로그인 페이지로 이동 후 로그인을 하면 원래 게시글이 아닌 메인 페이지로 이동되어 다시 그 게시글을 찾아가야 했던 불편한 경험이 있었는데, 그 문제점을 방지하기 위함이었다.
(비로그인 유저) 댓글 창 클릭 → 로그인 필요 모달 띄우기 → '확인' 클릭 시 로그인 페이지로 이동
→ 해당 로그인 페이지에서 로그인한 경우 보던 상세페이지로 리다이렉트 이동
로그인 페이지의 URL을 보면 리다이렉트 주소가 쿼리스트링으로 들어가 있으며, 이 주소값을 가지고 원래 보던 페이지로 돌아갈 수 있게 된다. 그런데 원래의 쿼리스트링이 아닌 이상한 값으로 들어가 있는데, 쿼리스트링에는?라는 특수기호가 들어가 있음으로 이를 안전하게 처리하기 위해 encodeURIComponent와 decodeURIComponent를 이용해 인코딩-디코딩 방식을 이용하였다.
이렇게 다시 로그인하고 오면 댓글창의 placeholder 값이 '로그인이 필요합니다'가 아닌 '방문 기록을 남겨주세요'로 변하게 신경 썼다. 댓글도 아무것도 입력하지 않거나, 공백만 입력될 경우 댓글을 등록할 수 없도록 구현해 두었다.
문제점: 중첩 모달 구현
이번 프로젝트의 모달 컴포넌트는 모달 영역 밖인 Backdrop 부분을 누르거나 x 버튼을 누르면 모달이 닫히는 BigModal.jsx가 있었고, 확인/취소 버튼만 달려있는 Modal.jsx로 구성되었다.
그런데 중첩 모달을 띄운 이후 Modal 컴포넌트의 아무 곳이나 클릭했을 때 BigModal이 닫히며, Modal까지 덩달아 닫히는 형상이 발생했다... 도통 그 이유를 찾지 못해 또 튜터님을 찾아뵙고 나서야 그 이유를 알게 되었다. BigModal은 본인의 영역을 감지하고, 본인 영역의 바깥 부분을 클릭하면 닫히는 구조인데, Modal도 본인의 영역 밖으로 평가되는 것이 문제였다.
이걸 3D 구조로 보면 이해가 쉬운데, Modal이 BigModal과 분리되어 있는 것처럼 보이며, 마치 상위에 있는 것처럼 보이지만 Modal 또한 BigModal 내 영역으로 평가받기 때문이었다(지금 생각하면 이벤트 버블링이 상위로 전파된 게 아닌가 싶다) 물론 다른 로직을 사용하면 이 문제가 발생하지 않을 수도 있지만 현재의 내 로직상에선 해결이 불가능했기 때문에 BigModal의 영역 밖을 클릭했을 때 모달이 닫히는 기능은 제거하고, x버튼을 눌러서만 닫히게 하였다.
위기는 곧 기회! 오히려 좋아?
이렇게 바뀌게 된 로직은 우연 하게도 UX적으로 도움이 되었는데, 기존 댓글 입력란이 모달 하단에 있어 댓글 입력 도중 Backdrop을 잘못 클릭하면 창이 닫혀 불쾌한 경험을 줄 수 있었는데, 이제는 Backdrop 부분을 클릭해도 닫히지 않기에 더 안전하게 댓글을 작성할 수 있게 되었다. 장점이 단점이 되고, 단점이 장점이 될 수 있다더니 정말 이럴 때 쓰는 말인가 보다.
다음번엔 어떻게 해결? React Portal
이런 일이 이번에만 발생하라는 법이 없기 때문에 다음을 위한 해결방법을 찾아야 했다. 함께 문제를 찾아주시고 해결방법을 제시해 준 튜터님은 React Portal을 사용해 보는 것을 권장해 주셨다.
Portal은 부모 컴포넌트의 DOM 계층 구조 바깥에 있는 DOM 노드로 자식을 렌더링 하는
최고의 방법을 제공합니다. - React 공식문서
React는 모든 요소가 root를 통해 렌더링 된다면, Portal은 아래와 같은 구조를 가져 모달마다 각자의 영역을 확실하게 확보할 수 있다.
이 방법을 사용하면 더 안정적으로 modal을 구현할 수 있을 것 같아 다음 프로젝트 때 구현해 보는 것을 목표로 삼고 있다. 이번 기회에 다른 블로그와 문서들을 보니 실제로 많은 곳에서 Portal을 사용해 모달을 구현하는 걸 볼 수 있었고, 그만큼 효과는 보증된 방식이기에 더욱 신뢰하고 사용할 마음이 생겼다.
그 외에도...
이 외에도 반응형으로 어떤 크기에서도 안정적으로 콘텐츠를 확인할 수 있게 구현했고, 댓글도 위에서부터 최신순으로 구현하였다. 처음에 쉽게 보았던 상세 페이지 모달 기능이었는데 이번 기회에 매우 많은 기술적 고민과 해결 방법을 찾으며 한층 더 프론트엔드와 친숙해진 것 같다.
예상치 못한 일도 많았지만 여러 기술적 문제가 발생하니 해결하기 위해 여러 방면으로 알아가는 과정이 되게 재밌었고, 좋은 팀원들을 만나 재밌고 든든하게 프로젝트에 집중할 수 있어 더욱 좋았다. 최종 프로젝트 전 마지막 랜덤 팀 구성인데 다음 팀도 좋은 분들을 많이 만났으면 좋겠다~!!
'TIL' 카테고리의 다른 글
[2024.06.25] 프로그래머스_예산(Summer/Winter Coding(~2018)) (0) | 2024.06.26 |
---|---|
[2024.06.24] 타입스크립트 개인 주차 과제 (0) | 2024.06.26 |
[2024.06.20] 모달에 Query string을 사용해 주소값 부여하기 (0) | 2024.06.21 |
[2024.06.19] 상세페이지 모달 UI구성 + 공통 컴포넌트에 대한 고민 (0) | 2024.06.21 |
[2024.06.18] JS Deep Dive_27. 배열 + 문자열 계산이 비효율적인 이유 (0) | 2024.06.19 |