Realays Logo Realays
← 블로그 목록으로
DevLog 2025. 11. 26.

[Dalendar DevLog 4] 핵심 기능 구현 2 (프론트엔드 & UI)

React Native로 직관적인 달력 UI를 구현하는 과정입니다. FlatList를 활용한 무한 스크롤과 컴포넌트 재사용성 극대화 전략을 소개합니다.

[Dalendar DevLog 4] 핵심 기능 구현 2 (프론트엔드 & UI)

4편: 핵심 기능 구현 2 (프론트엔드 & UI)

1. 시리즈의 시작: 직관적인 UI를 향한 첫걸음

안녕하세요, React Native 달력 앱 만들기 시리즈 4편입니다. 지난 편까지는 앱의 기본 설정과 데이터 구조에 대해 알아보았습니다. 이번 편에서는 사용자가 직접 마주하고 상호작용하는 달력의 프론트엔드, 즉 UI 구현에 대해 집중적으로 다루겠습니다. 모든 구현은 React Native와 Expo 환경을 기반으로 진행됩니다.

앱 개발 초기 단계에서 가장 중요하게 생각했던 목표는 ‘직관적인 사용자 경험’이었습니다. 이를 위해 **‘한 화면에 한 달이 보이고, 좌우 스크롤로 전달과 다음 달로 자유롭게 이동’**하는 방식을 핵심 UI로 결정했습니다. 사용자가 별도의 학습 없이도 자연스럽게 달력을 탐색할 수 있도록 하는 것이 목표였습니다.

2. 달력 UI의 핵심 구조: 컴포넌트 재사용성 극대화

효율적인 달력 UI를 위해, 우리는 중첩된 컴포넌트 구조를 채택했습니다. 이 방식은 ‘컴포넌트 재사용’을 통해 시스템 자원을 효율적으로 사용하여 성능을 최적화하는 것이 핵심입니다.

React Native의 FlatList 컴포넌트는 화면에 보이거나 가까이 있는 아이템만 렌더링하고, 멀리 스크롤된 아이템은 메모리에서 제거(unmount)하는 ‘가상화(virtualization)‘를 통해 이를 구현합니다. 이는 네이티브의 RecyclerView가 최소한의 뷰홀더(틀)를 만들어 데이터를 바꿔가며 재활용하는 방식과 동일한 원리입니다.

이를 바탕으로 저희 앱은 다음과 같은 2단계 컴포넌트 구조를 채택했습니다.

  1. 월(Month) 스크롤 뷰: 최상위 레벨의 컴포넌트로, 좌우로 스크롤됩니다. 한 화면에는 오직 하나의 ‘월’ 아이템만 보이도록 구성하여 사용자가 월 단위로 명확하게 탐색할 수 있도록 합니다. 이는 <FlatList horizontal pagingEnabled ... />와 같은 컴포넌트를 사용하면 효율적으로 구현할 수 있습니다.
  2. 일(Day) 그리드 뷰: 각각의 ‘월’ 아이템 내부에 위치하는 컴포넌트입니다. 한 달의 날짜들을 6행 7열, 총 42개의 격자 형태로 표시하여 달력의 시각적 형태를 완성합니다.

3. ‘무한 스크롤’ 월 달력 구현하기

사용자가 과거와 미래를 제약 없이 탐색할 수 있도록 ‘무한 스크롤’ 기능을 구현했습니다. 이는 실제로 무한한 데이터를 로딩하는 것이 아니라, 사용자가 그렇게 느끼도록 만드는 일종의 트릭입니다.

핵심 원리는 FlatList의 시작 위치를 아주 큰 정수 값의 중간 지점으로 설정하는 것입니다. initialScrollIndex prop을 활용하면 이 트릭을 간단하게 구현할 수 있습니다.

const INITIAL_INDEX = Math.floor(Number.MAX_SAFE_INTEGER / 2);
// ...
<FlatList
  // ... other props
  initialScrollIndex={INITIAL_INDEX}
/>;

이렇게 하면 사용자는 양쪽 방향으로 사실상 무한대에 가깝게 스크롤할 수 있는 경험을 하게 됩니다.

월 스크롤 뷰의 각 아이템(position)에 해당하는 연도와 월을 계산하는 로직은 ‘중앙으로부터의 오프셋’ 개념을 사용하면 직관적으로 구현할 수 있습니다.

  1. INITIAL_INDEX를 ‘기준점(center)‘으로 설정하고, 이 기준점이 현재 날짜의 월에 해당하도록 매핑합니다.
  2. FlatList에 의해 렌더링 되는 각 아이템의 position에 대해, 기준점과의 오프셋을 계산합니다: const monthOffset = position - center;
  3. 현재 월에 monthOffset 값을 더하거나 빼서 해당 아이템이 표시해야 할 연도와 월의 날짜 데이터를 동적으로 생성합니다.

4. 한 달의 날짜 그리드 생성 로직

특정 연도와 월이 주어졌을 때, 화면에 표시될 6x7(42개) 그리드를 채울 날짜 데이터를 생성하는 로직은 달력 구현의 핵심입니다.

이 과정은 다음과 같이 진행됩니다.

  1. 먼저 42개의 날짜 객체를 담을 빈 배열을 생성합니다.
  2. 가장 중요한 단계는 주어진 ‘월의 1일이 무슨 요일인지’ 파악하는 것입니다. JavaScript의 Date 객체에서 getDay() 메소드는 일요일을 0, 월요일을 1, … 토요일을 6으로 반환합니다.
  3. 1일이 속한 주의 첫 번째 날(일요일)을 계산합니다. 이는 ‘1일’에서 ‘1일의 요일 인덱스’만큼 날짜를 뒤로 이동시켜 구할 수 있습니다.
  4. 계산된 시작 날짜(일요일)부터 하루씩 더해가며 6주 동안, 즉 총 42개의 날짜 데이터를 순차적으로 배열에 채워 넣습니다.

예를 들어, 2024년 12월 1일은 일요일(요일 인덱스 0)입니다. 따라서 그리드의 시작 날짜는 12월 1일에서 0일을 뺀 12월 1일이 됩니다. 만약 1일이 수요일(인덱스 3)이었다면, 시작 날짜는 1일에서 3일을 뺀 이전 달의 28일이 됩니다. 이 간단한 예시는 로직의 핵심을 명확하게 보여줍니다.

5. 마무리하며: 구조적 완성

이번 포스트를 통해 우리는 달력 앱의 핵심적인 프론트엔드 구조를 완성했습니다. 컴포넌트 재사용성을 고려한 이중 구조를 설계하고, 무한 스크롤을 통해 월을 탐색하는 로직과 특정 월의 날짜 그리드를 생성하는 데이터 로직까지 구현했습니다.

이로써 기본적인 형태를 갖춘 달력이 성공적으로 화면에 나타나게 되었습니다. 물론 아직은 뼈대만 갖춘 상태입니다. 다음 단계에서는 이 구조 위에 실제 일정 데이터를 입출력하고 관리하는 기능을 구현하여 달력의 본질적인 역할을 채워나갈 예정입니다.

관련 포스트