특히 사용자 입장에서는 “언제 가능한지”, “예약했는지”, “상태는 어떤지”를 한눈에 확인할 수 있는 UI의 직관성이 매우 중요했고, 관리자 입장에서도 예약 현황을 효율적으로 관리할 수 있어야 했기 때문에 이번 파트에서는 날짜 기반 UI 구성, 예약 시각화, 전역 상태 및 비동기 처리가 핵심이 되었다.
구현 목표
[react-datepicker를 사용한 예약하기 모달]
체험 예약 기능에서 핵심이 되는 요소 중 하나는 날짜 선택 UI다. 사용자는 본인이 원하는 날짜를 명확하게 선택할 수 있어야 하며, 예약 가능한 날짜와 불가능한 날짜를 구분할 수 있어야 한다. 이를 위해 처음에는 단순한 input type="date"를 고려했으나, 다음과 같은 한계가 있었다
디자인 커스터마이징 제한
브라우저마다 input type="date"의 스타일이 다르며, 이를 커스터마이징하려면 복잡한 CSS 작업이 필요
예약 가능/불가 날짜 표시 기능 미제공
특정 날짜만 활성화하거나 비활성화하는 기능을 기본적으로 지원하지 않으며, 추가적인 자바스크립트 로직이 필요
월 변경 시 동적 예약 정보 반영
월 변경 시 예약 가능 여부 등 동적 데이터를 반영하려면 별도의 이벤트 핸들링과 상태 관리가 필요 기본 input type="date"는 이러한 동작을 미지원
react-datepicker 이란 ?
react-datepicker는 리액트 프로젝트에서 가장 많이 사용되는 날짜 선택 UI 컴포넌트 중 하나로, 간결한 디자인, 높은 커스터마이징 유연성, 그리고 시간 선택, 범위 선택, 필터링 등 다양한 기능을 제공한다.
| 기능 | 설명 |
|---|---|
| ✅ 날짜 선택 | 사용자가 클릭으로 날짜를 선택할 수 있는 달력 제공 |
| 🕓 시간 선택 지원 | 시간(Time) 선택 기능도 함께 제공 가능 |
| 📅 범위 선택 지원 | 시작일-종료일(date range) 선택 기능 |
| 🛠 커스터마이징 | 스타일, 포맷, 언어(localization) 등 다양한 옵션 지원 |
| 📌 날짜 필터링 | 특정 날짜만 선택 가능하도록 제약 가능 (예: 예약 가능한 날짜만 표시) |
| 📆 월 이동 제어 | onMonthChange 이벤트로 월 변경 시점 추적 가능 |
react-datepicker 현 프로젝트에서 사용 할 기능들
- highlightDates
- onMonthChange
- renderCustomHeader
- dayClassName
- minDate
- locale

예약 가능한 날짜 강조하는 기능으로 data.schedules을 외부에서 받아 예약 가능한 날짜들을 하이라이트
현재 보고 있는 달이 변경되었을 때 이벤트 감지 → 전역 상태 관리(Zustand)를 통해 selectMonth 업데이트

기본 캘린더 헤더 대신 커스텀 컴포넌트로 교체 → 좌우 버튼, 월/년 표시 디자인 자유롭게 구현 가능

개별 날짜 스타일을 지정할 수 있는 함수 → 현재 달은 기본 스타일, 이전/다음 달은 흐리게 표시
선택할 수 있는 최소 날짜 제한 → 오늘 이전 날짜는 모두 비활성화

요일 표시 포맷 등 현지화 설정 → 영어 요일을 Su, Mo 등 짧은 형식으로 커스터마이징
날짜만 선택할 수 있었던 기존의 datepicker 방식은 전체 일정을 파악하는 데 한계가 있었고, 특히 날짜별 예약 수나 상태를 확인하기엔 부적합했다.(예약 상태에 따른 이벤트 처리) react-datepicker 대신 react-big-calendar를 도입하여 월간 단위의 예약 현황을 시각적으로 한눈에 확인할 수 있는 UI를 구성했다.
전체 예약 현황을 한눈에 시각화하기 어렵다
→ datepicker는 단일 날짜 중심이며, 다수의 이벤트(예약)를 직관적으로 표현하기에 한계가 있음
예약 상태에 따라 색상 구분 등 복잡한 UI 조건을 구현하기 어려움
→ dayClassName이나 highlightDates만으로는 정보 표현의 한계
이벤트 클릭, 월간 전환, 사용자 정의 헤더 등의 유연한 캘린더 구성 필요
→ UX/기능 확장을 위해 react-big-calendar 도입
react-big-calendar란?
date-fns나 moment와 함께 사용하여 로케일 설정과 날짜 계산도 수월하게 처리할 수 있다.
react-big-calendar 현 프로젝트에서 사용 할 기능들
- CustomEvent
- CustomToolbar
- handleSelectSlot
- dateHeader

예약은 세 가지 상태(대기, 승인, 완료)로 나뉘며, 각각을 다른 색상 박스로 시각화하였다.
이렇게 각 이벤트에 대해 시각적으로 구분된 정보를 제공하여 예약 현황 파악을 쉽게 했다.

기본 툴바 대신 직접 만든 툴바를 적용하여, 사용자 경험에 맞춘 내비게이션을 제공했다.

사용자가 날짜를 클릭하면 해당 날짜의 예약 정보를 모달로 보여주는 구조를 구현했다

날짜 셀 위에 예약 상태에 따른 작은 원 아이콘을 표시하여, 한눈에 해당 날짜에 예약이 있는지 시각적으로 표현했다
react-big-calendar 을 사용하면서 느낀점
높은 커스터마이징 유연성 (이벤트, 툴바, 헤더 등) 특히 이벤트 부분은 UI 부분에서 react-datepicker 보다 할 수 있는 영역이 많아 좋았다.
사용자가 날짜를 선택하거나 상세 예약 정보를 확인하는 흐름은 단순한 UI 상호작용을 넘어 다양한 상태와 비동기 데이터의 흐름이 얽혀 있는 구조다. 이를 보다 일관성 있게 관리하기 위해, Zustand사용했다.
Zustand 사용
사용자가 날짜를 클릭하거나 예약 상세를 선택할 때마다 전역 상태가 일관되게 유지될 수 있도록 Zustand를 활용했다. 이 덕분에 복잡한 prop 전달 없이도 다양한 컴포넌트 간 데이터 연동이 가능했다.
캘린더 및 예약 시스템 구현 트러블 슈팅
react-datepicker와 react-big-calendar 모두 사용자 친화적이고 강력한 기능을 제공하지만, 디자인 시스템에 맞춰 커스터마이징하려고 할 때 큰 장벽이 있었다.
▪ 라이브러리 내부에서 컴포넌트 구조가 정해져 있음
▪ className만 던져주는 구조로, 세부 엘리먼트 접근이 제한적
▪ 특히 react-big-calendar는 각 날짜 셀, 이벤트 항목, 툴바 등의 마크업 구조가 고정돼 있어 디자인 시스템과 정확히 일치하는 UI를 만들기 어려움
▪ 라이브러리에서 내부적으로 사용 중인 클래스명을 파악하여 CSS를 override하는 방식으로 처리
▪ react-big-calendar는 components prop을 통해 각 UI 부분을 커스터마이징할 수 있도록 되어 있어서, 아래와 같이 CustomToolbar, CustomEvent, dateHeader 등을 직접 정의해 대체
▪ dayPropGetter, eventPropGetter 등을 활용해서 날짜 또는 이벤트 별로 조건부 스타일링을 적용할 수 있도록 설계
기성 라이브러리를 사용하면 개발 속도는 빨라지지만, 진행하고 있는 프로젝트의 디자인 시스템과의 통일성을 맞추려면 CSS 커스터마이징은 반드시 넘어야 할 허들이라는 걸 실감했다. 특히 react-big-calendar는 구조 자체가 유연하게 열려 있지 않기 때문에, override 방식 + component 분리 렌더링 전략을 병행해야 했다. 결과적으로는 커스텀 컴포넌트 분리 덕분에 유지보수도 용이해졌고, 동일한 구조에서 다양한 뷰포트 대응까지 확장 가능했다.
캘린더 및 예약 시스템 구현을 마치며 느낀 점
라이브러리는 빠른 개발을 가능하게 해주지만, 커스터마이징과 유지보수 측면에서는 신중한 판단이 필요하다는 점을 절실히 체감했다. react-big-calendar와 react-datepicker 모두 UI 구성에는 강력했지만, 내부 클래스나 컴포넌트 구조에 접근하는 데 제한이 있었고, 디자인 시스템과의 통일성을 확보하기 위해 많은 시간과 고민이 필요했다.
결국 커스텀 컴포넌트 렌더링(components, renderHeader, dayClassName 등)을 적극 활용하며 라이브러리를 우리 UI 설계에 맞게 가져오는 방식으로 해결해야 했다. 이 과정에서 단순 사용자가 아닌, 라이브러리를 통제하는 설계자로서의 시야를 확장할 수 있었다.