요즘 공부 목적으로 겸사겸사 하는 프로젝트가 있는데, 날짜와 시간을 선택하는 그럴 듯한 컴포넌트가 필요했다. 감사하게도 npm 모듈 중에 이를 사용하기 쉽도록 만들어 놓은 (커스텀도 매우 간단!) 것이 있어 해당 모듈을 사용하며 뭔가 정리하고 싶어져서 글을 쓴다.
import React, { useState } from "react";
import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";
const Example = () => {
const [startDate, setStartDate] = useState(new Date());
return (
<DatePicker
selected={startDate}
onChange={(date) => setStartDate(date)}
/>
);
};
공식 문서에 나와있는 코드이다. 이렇게 하고 해당 컴포넌트를 렌더링해주면 위 캡처화면에서와 같이 기본적인 datepicker 틀을 만나볼 수 있다. 나는 이제 이 기본 틀을 커스텀 하려고 한다.
커스텀하기 위해서는 시간을 다루는 함수를 많이 사용해야 하는데, 우선 date-fns 모듈도 다운 받아주자. 커스텀할 때 유용하게 쓰인다.
위에서의 Example 컴토넌트를 위와 같이 수정해보자. 캘린더의 글씨와 날짜는 한글로 표시되며 날짜가 출력되는 형태도 바뀐다. 그리고 화살표를 제거하였고 오늘 날짜보다 이전 날짜는 선택하지 못하게 한다. 마지막으로 날짜가 뜨는 인풋 박스도 예쁘게 커스텀한다.
import React, { useState } from "react";
import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";
import Form from "react-bootstrap/Form";
import { ko } from "date-fns/esm/locale";
const Example = () => {
const [startDate, setStartDate] = useState(new Date());
return (
<DatePicker
selected={startDate}
onChange={(date) => setStartDate(date)}
locale={ko} // 한글로 변경
dateFormat="yyyy.MM.dd (eee)" // 시간 포맷 변경
showPopperArrow={false} // 화살표 변경
minDate={new Date()} // 오늘 날짜 전은 선택 못하게
customInput={ // 날짜 뜨는 인풋 커스텀
<Form.Control as="textarea" rows={1} style={{width:"250px"}}/>
}
/>
);
};
날짜가 선택됐을 때 모양과 색깔을 바꾸고 싶다면 CSS를 수정해주면 된다. 그런데 나의 경우 이 방법을 사용하면 살짝 버벅거렸는데 끝내 이유를 끝내 알아내지 못해 CSS에서 important!를 사용했다. (important!는 최대한 남발하지 말도록 하자 ㅠㅠ)
아래 코드를 보면 알 수 있듯이 선택한 날짜의 월과 일과, 달력에서의 월과 일이 같다면 해당 day의 calssName을 selected-day로 해주는 코드이다.
import React, { useState } from "react";
import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";
import Form from "react-bootstrap/Form";
import { ko } from "date-fns/esm/locale";
import { getMonth, getDate } from "date-fns";
import "./day.css"
const Example = () => {
const [startDate, setStartDate] = useState(new Date());
return (
<DatePicker
selected={startDate}
onChange={(date) => setStartDate(date)}
locale={ko} // 한글로 변경
dateFormat="yyyy.MM.dd (eee)" // 시간 포맷 변경
showPopperArrow={false} // 화살표 변경
minDate={new Date()} // 오늘 날짜 전은 선택 못하게
customInput={ // 날짜 뜨는 인풋 커스텀
<Form.Control as="textarea" rows={1} style={{width:"250px"}}/>
}
dayClassName={(d) =>
getDate(d) === getDate(startDate) && getMonth(d) === getMonth(startDate)
? 'normal-day selected-day'
: 'normal-day'
}
/>
);
};
.normal-day {
background: white !important;
color: black !important;
width: 28px;
height: 28px;
line-height: 1.8;
text-align: center;
padding: 2px !important;
}
.selected-day {
background: navy !important;
color: white !important;
border-radius: 50% !important;
font-weight: 700;
}
나는 모임의 제목과 날짜를 정해서 등록하는 기능을 만들고 있었다. 그럼 모임 form 컴포넌트는 (부모 컴포넌트) datepicker 컴포넌트를 (자식 컴포넌트) 감싸고 있다. 따라서 선택된 날짜를 자식 컴포넌트에서 부모 컴포넌트로 넘겨줘야 했다.
그런데 선택된 날짜를 부모에게 바로 넘겨주니 이런 오류를 만날 수 있었다. 😒 그니까 이제 Object는 React에서 자식이 될 수 없다는 거다. 그렇다. datepicker로 선택된 날짜의 타입은 Object이다.
따라서 난 아래와 같이 String으로 변환해주어서 부모 컴포넌트로 전달해주었다. 이때 또 아까 썼던 date-fns 모듈이 유용하게 쓰인다.
import { getMonth, getDate, getDay } from "date-fns";
function seletTime() {
let Days = ['일', '월', '화', '수', '목', '금', '토'];
let Month = getMonth(startDate) + 1;
let Date = getDate(startDate);
let Day = Days[getDay(startDate)];
// 오브젝트는 전달 안돼서 string으로 변환
props.setClubTime(String(Month + "." + Date + " (" + Day + ")"))
}