072DATA

📅 아주아주 간단한 달력 구현 본문

FrontEnd/React

📅 아주아주 간단한 달력 구현

0720 2024. 10. 31. 01:04

 

오늘은 달력을 구현했는데  useCalendar라는 훅을 만들어서

달력에 관련된 로직을 관리하여 꽤 깔끔하게 설계가 된듯하다

아직까지는 이벤트 관련 로직이 없어서 UI 정도만 설계했다

다음 업데이트 해야할 사항으로 각 날짜별로 통계를 내려주고 해당 월의 통합 데이터까지 출력해야 한다

 

 

🛠️ 전체 구조 및 기술 스택

  • React와 TypeScript를 사용한 달력 구현
  • dayjs 라이브러리로 날짜 처리
  • Custom Hook을 통한 로직 관리
  • Tailwind CSS로 스타일링

 

 

💡 주요 로직 분석

1. Custom Hook (useCalendar)

상태 관리

const [currentMonth, setCurrentMonth] = useState(dayjs());

 

  • 현재 표시되는 월을 상태로 관리
  • dayjs 인스턴스를 초기값으로 설정

dayjs는 JavaScript 기반의 경량 날짜/시간 라이브러리로,

Moment.js의 현대적 대안이며 체이닝 API와 간단한 날짜 조작 기능을 제공한다고 함

 

 

날짜 데이터 생성 로직

const getDatesInMonth = (monthOffset: number): CalendarData => {
  const targetMonth = currentMonth.add(monthOffset, "month");
  const startOfCalendar = targetMonth.startOf("month").startOf("week");
  const endOfCalendar = targetMonth.endOf("month").endOf("week");
  // ...
}

 

 

targetMonth로 보여줄 월을 결정한 뒤,

startOfCalendar는 해당 월의 첫째 주 일요일을,

endOfCalendar는 마지막 주 토요일을 찾음

이렇게 하면 달력 그리드에 깔끔하게 표시할 수 있는 전체 날짜 범위가 나옴

 

날짜 배열 생성

 

const dates: DateInfo[] = [];
let day = startOfCalendar;
while (day.isBefore(endOfCalendar) || dates.length % 7 !== 0) {
  dates.push({
    isInCurrentMonth: day.month() === targetMonth.month(),
    day
  });
  day = day.add(1, "day");
}

 

 

while 루프로 시작일부터 종료일까지 순회하고

각 날짜마다 현재 월 포함 여부 체크

7의 배수로 맞추어 달력 완성함

 

🔄 상태 변경 함수

 

const handleMonthChange = (offset: number) => {
  setCurrentMonth(currentMonth.add(offset, "month"));
};

const handleYearChange = (offset: number) => {
  setCurrentMonth(currentMonth.add(offset, "year"));
};
  • 월 단위 이동과 년 단위 이동 기능 구현
  • offset 값으로 이동 방향과 크기 결정

 

2. Calendar 컴포넌트 구현]

 

const { currentMonth, getDatesInMonth, handleMonthChange } = useCalendar();
const { weeks } = getDatesInMonth(0);

 

 

 

 

 

  • useCalendar 훅에서 필요한 기능들 가져오기
  • 현재 월의 주 단위 데이터 계산 -> UI 때문에 주 단위의 데이터가 필요했음

렌더링 구조

  1. 헤더 영역
    • 연/월 표시
    • 이전/다음 월 이동 버튼
  2. 캘린더 그리드
    • 요일 헤더
    • 주 단위로 날짜 표시
    • 각 날짜 셀에 추가 정보 표시

이런 느낌으로  렌더링 구조를 잡으면 됨 ( 캘린더 구조만 알면 될듯 )

 

 

🎨 스타일링 특징

<div className="grid grid-cols-7 bg-gray-200 border-2 border-gray-300">
  {week.map(({ day, isInCurrentMonth }) => (
    <div className={`
      flex flex-col items-center p-4
      ${!isInCurrentMonth ? "text-gray-300" : ""}
      hover:bg-gray-300 transition-colors
    `}>

 

 

 

  • Tailwind CSS 활용
  • Grid 시스템으로 7칸 구성
  • 현재 월 여부에 따른 스타일 차이
  • 호버 효과 적용

 

 

⚙️ 성능 고려사항

  1. 날짜 계산 최적화
    • 불필요한 재계산 방지
    • 캐싱 전략 검토 필요
  2. 렌더링 최적화
    • 컴포넌트 분리 고려
    • 메모이제이션 적용 검토