드디어 졸업을 했다..! 취업은 언제,,? ㅎ..
프로젝트를 진행 중에 손쉽게 날짜를 선택할 수 있도록 캘린더(달력)를 구현하려고 하였다.
캘린더를 사용하는 일은 많으니까 라이브러리를 여러 가지 찾아보았으나... 구현에 있어 몇 가지 불편함이 있었다.
라이브러리를 왜 쓰지 않으셨습니까?!
1. 커스터마이징 등의 사용법에 대한 설명이 부족하다.
관련된 설명이 부족하다!
물론 나의 문해력이 부족해서 그럴 수도 있지만,, 다른 라이브러리에 비해 설명이 부족하다고 생각한다.
어떠한 기능을 사용하고 싶을 때 찾기가 굉장히 힘들었다.
2. 프로젝트가 무거워지는 걸 원치 않는다.
라이브러리를 추가할 수록 프로젝트의 무게가 점점 무거워지는 걸 원치 않는다.
최종적으로 해당 브라우저를 열 때 성능 저하가 생길 수 있기 때문이다.
프로젝트에서 사용하는 기능은 별로 없는 것이 비해, 라이브러리가 크다면 비효율적일 것이다.
그래서 캘린더를 어떻게 구현하였을까?!
시간이 지나니 코테에서 무언가를 구현하는 것과 살짝 비슷했다.
코테를 더 많이 공부했다면 더 수월하게 했을 수도..?
하여튼!
구현에 있어, 프로젝트에서 사용한 방법은 주마다 배열을 생성하여 날짜를 넣는 것이다.
첫 번째 배열에는, 이전 달의 날짜인 28일부터 31일까지, 현재 달의 1, 2, 3일에 대한 Date 타입의 값이 들어 있다.
마찬가지로 세 번째 배열에는, 11일부터 17일까지의 Date 타입 값이 들어 있다.
이러한 배열을 순회하여 차례로 나타내는 방법을 활용하였다.
코드 확인
우선 new Date()를 통해 현재 날짜를 useState에 담아둔다.
const [currentDate, setCurrentDate] = useState(new Date());
const year = currentDate.getFullYear();
const month = currentDate.getMonth();
달력에 표시될 첫날과 마지막 날 찾기
달력에 표시될 첫 날과 마지막 날이 필요하다.
위에서 보인 이미지처럼 달력의 첫날은 1일이 아닌, 이전 달의 28일이다.
// 현재 달의 첫 날
const firstDayOfMonth = new Date(year, month, 1);
// 달력 시작 날짜를 현재 달의 첫 날의 주의 일요일로 설정
const startDay = new Date(firstDayOfMonth);
startDay.setDate(1 - firstDayOfMonth.getDay());
firstDayOfMonth.getDay()는 현재 달의 첫 날짜의 요일을 숫자로 반환한다.
일요일은 0, 월요일은 1, ..., 토요일은 6으로 표현된다.
예를 들어, 만약 5월 1일이 수요일이라면 3을 반환한다.
해당 코드는 현재 달의 첫 날짜가 속한 주의 일요일 날짜, 즉 달력에 표시될 첫날을 나타낸다.
만약 현재 달의 첫 날짜가 수요일이라면, (1 - 3) 계산을 통해 -2가 된다.
이는 현재 달의 첫 날짜보다 2일 전, 즉 그 주의 일요일을 의미한다.
startDay.setDate(-2) -> 현재 달의 첫 날짜보다 이틀 전
// 현재 달의 마지막 날
const lastDayOfMonth = new Date(year, month + 1, 0);
// 달력 끝 날짜를 현재 달의 마지막 날의 주의 토요일로 설정
const endDay = new Date(lastDayOfMonth);
endDay.setDate(lastDayOfMonth.getDate() + (6 - lastDayOfMonth.getDay()));
위 코드처럼 new Date의 세 번째 인자가 0이라면 해당 달의 마지막 날을 불러온다.
위 코드는 달력의 마지막 날짜를 현재 달의 마지막 날짜가 속한 주의 토요일로 설정한다.
현재 달의 마지막 날짜가 목요일이라면, lastDayOfMonth.getDay()는 4를 반환한다.
이때 (6 - 4) 계산을 통해 2가 되며, 현재 달의 마지막 날짜에서 2일 후, 즉 그 주의 토요일을 의미한다.
만약 현재 달의 마지막 날이 1월 31일이라면, 구현할 달력에는 2일 후인 2월 2일까지 나타날 것이다.
주 단위로 배열에 날짜 넣기
이제 주 단위로 배열에 날짜를 넣을 차례이다.
해당 방법은 위에서 설명한 내용이 있으니 코드와 주석을 참고하면 될 것 같다.
/** startDay부터 endDay까지의 날짜를 주 단위로 그룹화하는 함수 */
const groupDatesByWeek = (startDay: Date, endDay: Date) => {
const weeks = []; // 최종적으로 주 단위로 그룹화된 날짜 배열들을 저장할 배열
let currentWeek = []; // 현재 처리 중인 주를 나타내는 배열
let currentDate = new Date(startDay); // 반복 처리를 위한 현재 날짜 변수, 시작 날짜로 초기화
// 시작 날짜부터 끝 날짜까지 반복
while (currentDate <= endDay) {
currentWeek.push(new Date(currentDate)); // 현재 날짜를 현재 주에 추가
// 현재 주가 7일을 모두 채웠거나 현재 날짜가 토요일인 경우
if (currentWeek.length === 7 || currentDate.getDay() === 6) {
weeks.push(currentWeek); // 완성된 주를 weeks 배열에 추가
currentWeek = []; // 새로운 주를 시작하기 위해 currentWeek을 재초기화
}
currentDate.setDate(currentDate.getDate() + 1); // 현재 날짜를 다음 날로 변경
}
// 마지막 주 처리 (만약 남아있다면)
if (currentWeek.length > 0) {
weeks.push(currentWeek); // 남아 있는 날짜가 있다면 마지막 주로 weeks에 추가
}
return weeks; // 주 단위로 그룹화된 날짜 배열들을 반환
};
스타일만 잘 적용한다면...
짠!
추가로 이전 달, 다음 날로 넘기는 코드!
const handlePrevMonth = () => {
// 이전 달로 이동
setCurrentDate(
new Date(currentDate.getFullYear(), currentDate.getMonth() - 1, 1)
);
};
const handleNextMonth = () => {
// 다음 달로 이동
setCurrentDate(
new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 1)
);
};
끝!
오타, 글이나 코드 개선 이야기는 언제나 환영입니다!!!
'React' 카테고리의 다른 글
[React] useNavigate와 useLocation으로 페이지 간 데이터 전달하기 (0) | 2023.01.05 |
---|