react
와 moment.js
그리고 styled-component
를 이용하여 캘린더를 만들어 보도록 하겠다.
- JS 기본 제공 함수인
Date()
와 비슷하지만 더 편리하게 사용 할 수 있는 날짜,시간 라이브러리이다. moment()
라는 함수를 사용하며 리턴 값으로 날짜와 method들이 담겨있는 객체를 반환한다.
- 설치 방법
npm install moment --save
yarn add moment
- 기본 적으로 호출시 현재의 시간을 담은 객체를 리턴한다.
console.log(moment())
- 인자로 string 형태의 날짜를 넣어주면, 그 날짜를 담은 객체를 리턴해 준다.
console.log(moment("2019-05-11"))
moment()
객체에 method를 쓸 경우 원본 값이 바뀌기 때문에 복제해서 원본을 유지하는 역활을 한다.
moment().clone()
인자로 날짜의 형식을 받아서 moment()
객체를 문자열로 출력해준다.
console.log(moment().format("YYYY-MM"));
// 2022-08
console.log(moment().format("YYYY-MM-DD"));
// 2022-08-12
console.log(moment().format("MM-DD"));
// 08-12
console.log(moment().format("DD-MM"));
// 12-08
moment()
객체를 기준으로 인자로 받은 단위 기간의 처음과 끝을 알려준다.
ex) 오늘 기준 이번달의 첫날
console.log(moment().clone().startOf("month").format("YYYY-MM-DD"));
// 2022-08-01
ex) (오늘 기준 이번달의 첫날)을 기준으로 이번주의 첫날
console.log(moment().clone().startOf("month").startOf("week").format("YYYY-MM-DD"));
// 2022-07-31
moment()
객체를 기준으로 첫번째 인자와의 대소를 비교한다. 두번째 인자로는 비교할 단위를 받는다.
// endDay가 지금보다 이전인지 date단위로 비교
moment().isBefore(endDay, "day")
// endDay가 지금이랑 같은 달인지 month단위로 비교
moment().isSame(endDay, "month")
moment()
객체를 기준으로 첫번째 인자로 받은 값 만큼 두번째 인자 단위로 빼거나 더한다.
//오늘 보다 일주일 후
moment().add(1, "week")
//오늘 보다 3일 전
moment().subtract(3, "day")
앞서 배운 moment.js를 활용하면 오늘을 기준으로 이번달의 첫날과 마지막 날을 구할 수 있다.
moment().clone().startOf("month")
// 2022-08-01
moment().clone().endOf("month")
// 2022-08-31
하지만 달력에서는 이번달 뿐만일 아니라 첫날과 끝날이 속한 week의 날짜들을 전부 표시해줘야된다.
그렇다면 위에 코드에 .startOf("week")
와 .endOf("week")
를 추가해 보자
const startDay = moment().clone().startOf("month").startOf("week")
// 2022-07-31
const endDay = moment().clone().endOf("month").endOf("week")
// 2022-09-03
자 이제 이번달에 보여 줄 날짜들을 달력으로 만들기 좋게 2차원 리스트로 만들어보자
[week , week, week, week, ...]
의 형식으로
const day = startDay.clone().subtract(1, "day");
while (day.isBefore(endDay, "day")) {
calendar.push(
Array(7)
.fill(0)
.map(() => day.add(1, "day").clone())
);
}
- 달력의 처음 날짜인
startDay
보다 하루 전을day
라고 지정한 후 day
가endDay
가 될때 까지 while 문을 돌려보자- Array(7) 7개의 원소로 이루어진
week
배열을 0으로 채운 뒤 각각의 위치에day
의 값을 1일 씩 더해서 채워 준다. - 결과 적으로 달력의 형태를 가진 2차원 배열이 만들어진다.
위의 코드를 build.js
라는 로직으로 분리해 놓겠다.
//build.js
const buildCalendar = (value) => {
const startDay = value.clone().startOf("month").startOf("week");
const endDay = value.clone().endOf("month").endOf("week");
const day = startDay.clone().subtract(1, "day");
const calendar = [];
while (day.isBefore(endDay, "day")) {
calendar.push(
Array(7)
.fill(0)
.map(() => day.add(1, "day").clone())
);
}
return calendar;
};
export default buildCalendar;
이제 배열을 view상에 분배 해 보자
{calendar.map((week, w) => (
<Weeks key={"week" + w}>
{week.map((day, d) => (
<Day
day={day}
value={value}
events={events}
onChange={click ? onChange : () => {}}
key={"day" + w + d}
/>
))}
</Weeks>
))}