날짜를 선택하는 UI가 필요할 때가 있다.
여행사에서 비행기나 숙소 일정을 잡을 때도 있을 것이며, 수강신청 날짜를 검색하기 위해 특정 날짜를 선택해야할 수도 있다.
이럴 때 사용하는 UI를 Date Picker라고 많이 말한다.
React에서는 대표적으로 react-datepicker가 쓰인다.
npm install react-datepicker
을 통해 설치한다. (혹은 yarn add react-datepicker
)import DatePicker from "react-datepicker
으로 불러와 사용한다.<DatePicker />
로 사용할 수 있으며 props는 다음을 일반적으로 사용한다.
이름 | 자료형 | 설명 |
---|---|---|
startDate | Date? | 시작날짜(기간이 아닐때는 이 값이 기본값이 됨) |
endDate | Date? | 종료날짜(기간선택일 때만 사용) |
isClearable | bool? | 초기화할 수 있도록 초기화 버튼을 추가하는지에 대한 여부 |
placeholderText | String? | 값이 없을 때 가이드텍스트 |
minDate | Date? | 선택할 수 있는 날짜의 최소값 |
maxDate | Date? | 선택할 수 있는 날짜의 최대값 |
selectsRange | bool? | 기간선택을 할지 안할지에 대한 여부 |
onChange | event? | 선택한 날짜가 바뀌면 실행되는 콜백 함수(보통 여기에 setState 함수를 넣음) |
excludeDates | [Date] | 리스트에 들어있는 날짜들을 선택할 수 없도록 제외함 |
- 오늘부터 6개월 이내까지의 날짜에서 기간선택을 해야한다.
- 날짜를 선택하면 1주일 단위로만 기간을 선택할 수 있다.
위의 기능명세가 있다고 하면 어떻게 만들어야할까?
먼저 날짜를 상태로 저장해야하므로
const [startDate, setStartDate] = useState(null);
const [endDate, setEndDate] = useState(null);
const onChange = (dates) => {
const [start, end] = dates;
setStartDate(start);
setEndDate(end);
};
위와 같은 상태 2가지를 저장해야할 것이다.
그리고 처음은 시작날짜를 선택하면 onChange 함수가 작동되어 startDate값이 지정되고 endDate값은 null일 것이다.
종료날짜를 선택하면 onChange 함수가 작동되어 endDate값이 지정되어 startDate와 endDate 값 둘다 null이 아닐 것이다.
또한, 처음 시작날짜를 선택하지 않은 상태에선 모든 날짜를 자유롭게 선택이 가능해야한다.
시작날짜를 선택한 상태에선 시작날짜에서 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 12, 14일 후, ... 의 규칙으로 선택하지 못하도록 제외해야한다.
왜냐하면 기간이 1주일 단위라고 명세가 되어있으므로 시작날짜와 종료일자의 간격은 7배수-1`일
이기 때문이다.
이 흐름을 이해했다면 다음의 코드가 이해될 것이다.
import { useState } from "react";
import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";
function DateRangePicker() {
const [startDate, setStartDate] = useState(null);
const [endDate, setEndDate] = useState(null);
const onChange = (dates) => {
const [start, end] = dates;
setStartDate(start);
setEndDate(end);
};
return startDate == null ? (
<DatePicker
onChange={onChange}
minDate={new Date()}
maxDate={new Date(new Date().setMonth(new Date().getMonth() + 6))}
selectsRange
startDate={startDate}
endDate={endDate}
isClearable={true}
placeholderText="Select a date range"
/>
) : (
<DatePicker
onChange={onChange}
minDate={startDate}
maxDate={new Date(new Date().setMonth(new Date().getMonth() + 6))}
selectsRange
startDate={startDate}
endDate={endDate}
isClearable={true}
placeholderText="Select a date range"
calendarClassName="rasta-stripes"
excludeDates={[].concat(
Array.from(
{ length: 30 },
(_, i) =>
new Date(new Date().setDate(startDate.getDate() + 7 + i * 7)),
),
Array.from(
{ length: 30 },
(_, i) =>
new Date(new Date().setDate(startDate.getDate() + i * 7 + 1)),
),
Array.from(
{ length: 30 },
(_, i) =>
new Date(new Date().setDate(startDate.getDate() + i * 7 + 2)),
),
Array.from(
{ length: 30 },
(_, i) =>
new Date(new Date().setDate(startDate.getDate() + i * 7 + 3)),
),
Array.from(
{ length: 30 },
(_, i) =>
new Date(new Date().setDate(startDate.getDate() + i * 7 + 4)),
),
Array.from(
{ length: 30 },
(_, i) =>
new Date(new Date().setDate(startDate.getDate() + i * 7 + 5)),
),
)}
/>
);
}
export default DateRangePicker;