프로젝트: React YearMonth Picker

리액트 날짜선택 UI 라이브러리

img

프로젝트 기획 동기

사이드 프로젝트를 진행하는 과정에서 년·월을 선택할 수 있는 달력이 필요했습니다. 처음에는 npm 패키지들을 찾아보았지만, 제 요구를 정확히 충족하는 라이브러리는 없었습니다. 이 과정에서 저와 같은 불편을 느낀 개발자들이 분명 있을 것이라 생각했고, 이에 직접 라이브러리를 개발하기로 결정하였습니다.

사용한 기술

자바스크립트 빌드 툴, 번들러. Webpack과 비슷함

기능 소개

1. 날짜를 선택하는 모달

버튼을 클릭하면 모달이 켜지고, 사용자가 원하는 날짜를 선택할 수 있는 기능을 구현하였습니다.

모달을 생성하는 방식으로는 React의 Portal 기능을 활용하였습니다. 제가 주로 사용하는 shadcn 라이브러리의 작동 원리를 분석해본 결과, 모달을 클릭하면 해당 <div>가 HTML 최상단에 위치하는 것을 확인하였습니다. 이를 구현하기 위해 Portal이 적절하다고 판단하였고, 실제로 코드를 분석해본 결과, 모달이 DOM 최상단에 생성되는 방식을 확인한 후 React Portal을 적용하였습니다.

모달은 화면의 다른 요소들로부터 영향을 받지 않고 독립적으로 동작해야 하기 때문에, 이러한 구조가 적절하다고 생각하여 동일한 방식을 적용하였습니다.

3. Github action을 이용한 CICD

GitHub Actions와 npm을 연동하여, 태그(tag)를 생성할 때마다 자동으로 배포가 이루어지도록 트리거를 설정하였습니다.

어려웠던 점

1. 버블링 그리고 캡처링

날짜 선택 버튼을 클릭했을 때 모달을 여는 기능은 비교적 간단하게 구현할 수 있었습니다. 버튼에 onClick 이벤트를 추가하면 되었기 때문입니다. 그러나 모달을 닫는 기능은 다소 까다로웠습니다. 이유는 모달을 닫는 방식이 2가지였기 때문입니다.

1. 버튼을 다시 클릭

2. 모달 외부 공간을 클릭

즉, 사용자가 화면을 클릭했을 때, 버튼을 클릭한 것인지, 날짜를 선택한 것인지, 외부 공간을 클릭한 것인지를 정확히 판별해야 했습니다. 특히, 외부 공간을 클릭했을 때는 모달만 닫고 다른 버튼 이벤트가 발동되지 않도록 처리해야 했습니다.

이 문제를 해결하기 위해, 이벤트 캡처 단계에서 외부를 클릭한 경우 이벤트가 버튼까지 전파되지 않도록 preventDefault를 설정하여 문제를 해결할 수 있었습니다.

처음에는 개념적으로만 알고 있던 이벤트 버블링을 실제로 구현하면서, 이를 고려하여 개발하는 과정이 어려웠습니다. 그러나 이런 상황에서 어떻게 이벤트 전파를 제어할 수 있는지 경험을 통해 배운 값진 시간이었습니다.

2. 반응형 페이지에 대응

모달의 위치는 아래 사진처럼 <button> 바로 아래에 absolute 속성을 사용하여 배치됩니다. 이 방식은 기본적으로 간단하게 구현할 수 있지만, 화면 크기가 변경될 경우 모달의 위치가 틀어질 위험이 있습니다.

이미지hard-2-d-2

처음에는 resize에 대응하기 위하여 상위 <div>에 position: relative를 설정 & 모달을 absolute로 배치 하는 방법을 고려하였습니다. 이 방식이라면 쉽게 해결할 수 있었지만, Portal을 사용하고 있었기 때문에 적용이 불가능했습니다.

이미지hard-2-d-4

이를 해결하기 위해 resizeObserver를 활용하여 화면 크기 변화를 감지하고, 모달을 여는 버튼의 위치를 동적으로 계산한 뒤, 여기에 5px을 추가하는 방식으로 정확한 위치를 유지하도록 구현하였습니다.

이를 해결하기 위해 resizeObserver를 활용하여 화면 크기 변화를 감지하고, 모달을 여는 버튼의 위치를 동적으로 계산한 뒤, 여기에 5px을 추가하는 방식으로 정확한 위치를 유지하도록 구현하였습니다.

이미지hard-2-d-7

이미지

image
image
image

링크