달력이 쉬워보이니?
솔직하게 말하자면 이 프로젝트를 마주하기 전까지 library를 쓰는 것은 내 스스로에게 패배(?) 하는 것이라고 생각하고 있었다.
그래서 남이 만들어 놓은 것을 가져다 쓰기보다 내가 직접 구현해야겠다! 라고 일정을 고려하지 않은 말도안되는 자신감을 가지고 있었고 하루종일 달력을 만들어보겠다고 시도한 결과 무한의 에러의 늪을 만나게 된다.
한 달력을 손대면 다른 달력도 다같이 영향을 받는 암울한 코드들...
이 블로그를 쓰기 전에도 다시금 시도해보자고 해보았지만 결국 원하는 결과를 얻지 못했다. 그 당시에 달력을 담당한 팀원분이 한분 더 계셨는데 그분에게 첫날을 다 맡겨놓은 꼴이 되어버려서 정말 죄송하다는 말씀밖에 드릴 수가 없다.
두번째 날부터는 그냥 수긍하고 라이브러리에 전력을 다하게 되었고, 현업에서도 그냥 내 개인공부가 아니고서야 시간이 부족하다면 라이브러리를 사용하는게 효율적임을 알게 되었으며
거기에 더불어서 라이브러리 그 자체를 분석하고 이것을 요구사항에 맞춰서 변형하는 것 역시 엄청나게 어려운 일임을 깨닫게 되었다.
1. mui
우선 처음에 라이브러리를 무엇을 사용할까 하다가 가장 유명한 material ui에 라이브러리가 존재하기에 이것을 사용하자고 서로 의견을 맞대었으나
라이브러리 설치 전에 어째서 경로에 "lab"이라는 단어가 붙어있는지를 미리 봤어야 헀다...
처음 등록할 당시에는 큰 어려움이 없이 진행할 수 있었다. 그냥 코드만 가져다가 쓰면 되었으니 말이다.
그런데, 이 내용을 커스터마이징해야하는 순간부터 지옥도가 펼쳐지게 되었다.
해당 내용이 아직 테스트본이다보니 원하는 기능이 많지도 않을 뿐더러 커스터마이징이 전혀 자유롭지 못했던 것이다.
그 덕택에 또 수시간을 고통을 받을수밖에 없었고 다른 방책을 사용하기로 결정하게
2. react-datepicker
그나마 최신이며, 커스터마이징이 아주 자유롭다고 알려진 이 라이브러리는 공식문서 역시 매우 친절한 편이긴 했다. 정정하자면 예시 자료가 친절한 편이었다.
공식 사이트에는 예시 자료만 무궁무진하게 많을 뿐 도대체 옵션이 뭘 의미하는지를 문서로 이야기해주질 않아서 또 한동안 옵션을 찾아 해메느라 고생했고, 여기에 더불어 디자인을 커스터마이징하려면 일일이 라이브러리 내부의 태그 클래스를 다 찾아서 직접 변경해야 했다...
우선 간단한 사용법은 아래와 같다.
import React, { useEffect, useState, Dispatch, SetStateAction } from "react";
import DatePicker from "react-datepicker"; // date picker이다
import "react-datepicker/dist/react-datepicker.css"; // 이렇게 가져와야 기본 디자인이 설정된다
import ko from "date-fns/locale/ko"; // 달력을 한글 지원으로 바꾸는 용도
import dayjs from "dayjs"; // 이쁘지 않게 들어오는 날짜를 손쉽게 변경용도
//참고로 dayjs로 "Sat Mar 19 2022 00:00:00 GMT+0900 (한국 표준시)" 와 같은 날짜를 넣어주면 내부 메서드 format을 이용해서 편하게 변경할 수 있다.
const [startDate, setStartDate] = useState<Date | null>(null);
const [endDate, setEndDate] = useState<Date | null>(null);
const [active, setActive] = useState(false);
const onChange = (dates: [Date, Date]) => {
const [start, end] = dates;
setStartDate(start);
setEndDate(end);
}; // datepicker을 두개로 사용하는 버전을 이용하면 onchange가 되는 순간 dates에 저렇게 배열이 들어온다.
const start = dayjs(startDate);
const end = dayjs(endDate);
const startFormat = start.format("YYYY-MM-DD");
const endFormat = end.format("YYYY-MM-DD");
// diff 맨 마지막 버튼부분에 얼마만큼의 날짜 차이가 나는지를 찾기 위해서이다.
// 타입정의 내용 안 설명을 보면 아래와 같다.
// * const date1 = dayjs('2019-01-25')
// * date1.diff('2018-06-05', 'month') // 7
const diff = Math.floor(end.diff(start, "day"));
return (
<DatePicker
selected={startDate} // 첫 클릭시 어떤 date 하이라이트할건지
startDate={startDate} // 상태관리 대상
endDate={endDate} // 상태관리 대상
onChange={onChange} // 클릭 변경시마다 인자에 date 배열 전달해줌
locale={ko} // 한국어버전사용
showPopperArrow={false} // date 위에 화살표 모양 없애기
selectsRange // 범위설정가능한 달력으로 변경
inline // 팝업이 아닌 inline으로 나오게 변경
monthsShown={2} // 달력 갯수 설정
minDate={new Date()} // 최소 날짜 이전 비활성화 기준
showDisabledMonthNavigation // 최소날 짜 이전 비활성화 옵션
renderCustomHeader={({
monthDate,
decreaseMonth,
increaseMonth,
prevMonthButtonDisabled,
nextMonthButtonDisabled,
}) => (
// 해당 아래는 달력의 헤더 추가부분이다.
<div className="custom-header">
<button
onClick={decreaseMonth}
disabled={prevMonthButtonDisabled}
>
<AiOutlineArrowLeft size={18} />
</button>
<div className="custom-month">
{monthDate.getFullYear()}년 {months[monthDate.getMonth()]}
</div>
<button
onClick={increaseMonth}
disabled={nextMonthButtonDisabled}
>
<AiOutlineArrowRight size={18} />
</button>
</div>
)}
/>
);
이렇게 달력 라이브러리를 이용하면 간편하게 달력 기능을 구현할 수 있다
그러나, 다시금 말하자면 디자인은 일일이 클래스를 확인해본 후 설정해줘야 한다