구글 캘린더 클론 토이 프로젝트
프로젝트 계기
📎 GitHub: https://github.com/wayandway/google-calendar
여러 일정 관리 웹앱을 사용해봤지만, 가장 기본적인 뼈대를 가진? 서비스는 구글 캘린더라고 생각했다. UI가 직관적이며, 반복 일정, DnD, 월/주/일 뷰 전환 같은 기능들이 자연스럽게 녹아 있어, 사용 흐름이 매우 매끄럽다.
이 경험을 직접 구현해보면 어떤 구조와 상태 흐름으로 이루어져 있을까 궁금했고, 달력 데이터를 직접 계산하고 비즈니스 로직을 설계하며 실제 서비스에 가까운 경험을 만들어보는 것을 목표로 프로젝트를 진행했다.
기능 요구사항 및 구현 목표
최소 기능 구현(MVP) 이후 점진적으로 확장하는 방식으로 개발했다.
기본 목표
- 월 달력 렌더링
- 날짜 클릭 → 일정 입력/저장/삭제
- 일정 리스트 표시
- 오늘 날짜 표시
- 이전/다음 달 이동
확장 목표
- Drag & Drop으로 일정 이동
- 반복 일정
- 주간/일간 뷰 전환
- 로컬스토리지 또는 DB 연동으로 일정 유지
주요 기술 스택
날짜 처리 로직을 직접 구현해보는 경험을 위해, Day.js는 최소한으로만 사용했다.
| 구분 | 기술 |
|---|---|
| 프레임워크 | React (TypeScript) |
| 스타일링 | TailwindCSS |
| 상태관리 | useState, Context API |
| 기타 | Day.js (날짜 처리) |
달력 렌더링 로직
월 달력을 렌더링하기 위해 필요한 주요 로직은 아래와 같다.
- 현재 년/월 기준으로 첫 번째 날짜와 마지막 날짜 계산
- 이전/다음 달 날짜 포함한 6주(42칸) 그리드 구성
- 오늘 날짜 하이라이트 처리
// 특정 월의 시작 요일, 마지막 날짜 계산
const startOfMonth = dayjs(currentDate).startOf("month");
const endOfMonth = dayjs(currentDate).endOf("month");
const startDay = startOfMonth.day(); // 시작 요일 (0~6)
const daysInMonth = endOfMonth.date();
이 로직을 기반으로 달력을 렌더링하면, 구글 캘린더처럼 항상 6줄로 안정적인 UI가 만들어진다.
일정 관리 방식
useState와 Context API로 전역 상태를 관리했다.
const [events, setEvents] = useState([]);
const addEvent = (newEvent) => {
setEvents([...events, newEvent]);
};
const deleteEvent = (id) => {
setEvents(events.filter((event) => event.id !== id));
};
리스트 구조 예시 ↓
[
{
"id": 1,
"date": "2025-01-11",
"title": "스터디 모임",
"time": "18:00"
}
]
일정 상태 구조를 미리 정의해두고 설계한 덕분에 확장 기능(예: 반복 일정, 시간대, 색상 라벨 추가)도 수월했다.
UI/UX 포인트
- 날짜 클릭 시 모달을 띄워 직관적으로 일정 입력
- 오늘 날짜는 파란색 테두리로 강조
- 일정이 있는 날짜에 점 표시 → 클릭하면 상세보기
- 헤더 좌우 버튼으로 빠른 월 이동
실제 구글 캘린더 UX를 참고하면서, 과하지 않고 익숙한 UI 스타일링을 목표로 했다.
트러블슈팅
1) 날짜 포맷 문제
초기엔 문자열 기반 날짜 비교에서 오류가 발생했다.
new Date() 기반 비교 대신 day.js 객체 비교로 해결했다.
2) 일정 렌더링 성능
초기에는 모든 이벤트를 전체 렌더링했지만, 날짜별 필터링 로직을 분리해 렌더링을 최적화했다.
3) 상태 분리
이벤트 입력 모달을 여러 컴포넌트에서 열기 위해 Context로 상태 구조 리팩토링
const CalendarContext = createContext();
상태를 중앙에서 관리하면서 훨씬 확장성과 유지보수성이 좋아졌다.
마무리하며
이번 프로젝트를 통해 달력 렌더링 구조, 날짜 계산 로직, 전역 상태 관리, UX 설계까지 캘린더 서비스의 핵심 기능 흐름을 직접 구현해볼 수 있었다.
특히 42칸 달력 구조, Context 기반 상태 관리, 모달 UI 설계 등을 구현하며 컴포넌트 구성과 상태 관리 방식에 대해 깊이 고민할 수 있었다.