develop

날짜 기능이 있는 게시판 만들기 with datepicker (2) - 기본 사용법, 활용법

crab. 2023. 2. 22. 19:18
  • 요구 사항들이 다 정리가 되었기에 우선 이 날짜 기능을 어떻게 구현할지를 정해야 했다.
  • 직접 구현할 것인지 아니면 라이브러리를 쓸 것 인지
  • 전에 패x에서 달력을 바닐라 자바스크립트로 만드는 강의를 본 기억이 있었지만
    • 그 강의는 단순히 달력기능까지만 나왔으며
    • 이번에는 복잡하게 날짜 데이터들을 가공해야하며
    • 무엇보다 시간제한이 걸려있기에(없었다면 바닐라 자바스크립트로 했었을 것 같다.. 실력향상에도 좋고 확장성도 좋고)
  • 라이브러리를 선택하기로 했다.
  • 라이브러리는 크게 react-calendar 와 react-datepicker가 있었는데 나는
    • react-datepicker의 레퍼런스 코드가 어느정도 있음
    • 공식사이트의 설명이 직관적임
  • 의 이유로 react-datepicker를 사용하기로 결정했다.

순서대로 구현해보자.

  • 막상 만들때는 페이지네이션도 써야 했기에 조금 해맸었지만 여기서는 날짜 관련만 이야기 해보고자 한다.
  • 우선 게시판에 크게 이벤트를 등록할 수 있어야 한다.
    • 그리고 이 이벤트에는 시작날짜, 시작시간, 끝시간 이렇게 3개의 input이 주어지고
    • 1개는 클릭하면 달력이
    • 2개는 시간이 나와야한다.
    • 처음에 날짜를 오늘로 했다면 처음 시간 input에는 현재시간 이전은 선택하면 안된다.
    • 시작시간을 정하기전에는 끝시간을 정할 수 없으며 시작시간이 정해지면 그 시간 이전시간들은 비활성화 된다.
    https://user-images.githubusercontent.com/87622597/220591767-b4d909c2-c7d0-40d9-a0cb-d6700c455b44.gif

datepicker 기본 사용법 및 스타일링

  • 우선은 import부터 시작하자면
import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";
import "../../../elements/DatePicker.css";
  • 이렇게 총 3개를 import 해오는 데 차례대로
    • datepicker
    • datepickre 기본 css
    • datepicker 커스텀 css 이다.
  • 3번째의 커스텀 css는
.react-datepicker__input-container input {
  width: 82px;
  height: 19px;
  padding: 5px 10px;
  background: #f5f5f5;
  border: 1px solid white;
  border-radius: 5px;
  font-size: 15px;
  font-weight: 400;
  text-align: center;
  color: #2b2b2b;
}

.react-datepicker {      
  font-size: 1.3rem !important;
}

.react-datepicker__current-month {
  font-size: 1.5rem !important; 
}

.react-datepicker__header {
  padding-top: 6px !important; 
}

.react-datepicker__day-name, .react-datepicker__day {
  margin: 0.5rem !important; 
}

.saturday {
  color: rgb(0, 0, 255) !important; 
}

.sunday {
  color: rgb(255, 0, 0) !important; 
}

.react-datepicker__day--disabled {
  color: #cccccc !important; 
}

.react-datepicker-wrapper {
  width: unset;
  /* margin-right: 16px; */
}

.react-datepicker__day--selected, .react-datepicker__day--in-selecting-range, .react-datepicker__day--in-range,
.react-datepicker__month-text--selected,
.react-datepicker__month-text--in-selecting-range,
.react-datepicker__month-text--in-range,
.react-datepicker__quarter-text--selected,
.react-datepicker__quarter-text--in-selecting-range,
.react-datepicker__quarter-text--in-range,
.react-datepicker__year-text--selected,
.react-datepicker__year-text--in-selecting-range,
.react-datepicker__year-text--in-range {
  background-color: black;
}

.react-datepicker__day--keyboard-selected,
.react-datepicker__month-text--keyboard-selected,
.react-datepicker__quarter-text--keyboard-selected,
.react-datepicker__year-text--keyboard-selected {
  background-color: black;
}
.react-datepicker__header {
  background-color: unset;
  border: none;
}

.react-datepicker__month-container {
  padding: 0.5rem;
}

.react-datepicker__day-names {
 color: #6b6b6b;
 font-weight: 500;
}

.react-datepicker__day--outside-month {
  color: #6b6b6b;
}

.react-datepicker__tab-loop {
  background-color: royalblue;
  position: absolute;

}
  • 이런식으로 원래 있던 datepicker의 클래스를 이용해 스타일링을 하는 방식이다.(사실 나도 아직 완벽히는 모른다..)
  • https://reactdatepicker.com/
  • 내가 공식문서를 사용한 형식은 우선 default를 따라가고 필요한 기능이 있을때 마다 공식문서를 참고하여 적용하는 방식이었다.
    • 사실 이렇게 라이브러리와 공식문서를 본격적으로 사용하는 게 처음이라 공식문서를 잘 활용하지 못하고 구글링으로 스택오버플로우를 많이 참고했었다.
    • 그리고는 정말 무수히도 많이 해메었다.
    • 과거에 공부를 할 때 꼭 공식문서를 제일 먼저 보라고 귀에 피가 나도록 들었지만 또 잘 지키지 못한 셈이다.
    • 후반에 들어서야 많은 삽질 끝에 공식문서를 참고하기 시작했는데 disabled같은 간단하지만 매우매우 유용했던 기능이나 customInput같은 살짝은 복잡한 기능도 사용할 수 있게 되었다.
    • 라이브러리를 사용할 때 막힌다면 공식문서를 먼저 찾아보는 것이 좋다라는 것을 깨달았고 응용이 중요하다는 것을 알았다.
  • 나의 완성형 코드는 다음과 같았다.
										<DatePicker
											className={
	                      startDateTrim && !startDate ? "trimError date" : "date"
	                    }
                      placeholderText="YYYY.MM.DD"
                      selected={startDate}
                      onChange={setStartDate}
                      showPopperArrow={false}
                      locale={ko} // 한글로 변경
                      dateFormat="yyyy.MM.dd" // 시간 포맷 변경
                      autoComplete="off"
                      selectsStart
                      minDate={new Date()}
                      endDate={endDate}
                      startDate={startDate}
                      ref={startDateRef}
                      onBlur={onBlurStartDateCheck}
                      customInput={<ExampleCustomInput />}
                    />
  • 이 코드가 나오기 까지 많은 시행착오가 있었는데
  • 우선 className같은 경우 나는 저렇게 className이라는 속성안에 삼항 연산자를 쓴 것이 아닌 밖에다가 썼다.
  • 즉, 원래는
								<DatePickerBox>
                  {startDateTrim && !startDate ? (
                    <ErrorDatePicker>
                      <DatePicker
                        className="trimError"
                        placeholderText="YYYY.MM.DD"
                        selected={startDate}
                        onChange={setStartDate}
                        showPopperArrow={false}
                        locale={ko} // 한글로 변경
                        dateFormat="yyyy.MM.dd" // 시간 포맷 변경
                        autoComplete="off"
                        selectsStart
                        minDate={new Date()}
                        endDate={endDate}
                        startDate={startDate}
                        ref={startDateRef}
                        onBlur={onBlurStartDateCheck}
                        customInput={<ExampleCustomInput />}
                        // style={{ border: "2px solid #ff0000" }}
                      />
                    </ErrorDatePicker>
                  ) : (
                    <DatePicker
                      placeholderText="YYYY.MM.DD"
                      selected={startDate}
                      onChange={setStartDate}
                      showPopperArrow={false}
                      locale={ko} // 한글로 변경
                      dateFormat="yyyy.MM.dd" // 시간 포맷 변경
                      autoComplete="off"
                      selectsStart
                      minDate={new Date()}
                      endDate={endDate}
                      startDate={startDate}
                      ref={startDateRef}
                      onBlur={onBlurStartDateCheck}
                      customInput={<ExampleCustomInput />}
                    />
                  )}
                </DatePickerBox>
  • 이런 느낌이었다..
  • 여기서도 다시 느껴지는게 나는 이번 기능을 구현하면서 삼항연산자를 잘 쓰지 못해 많은 삽질을 했고 또 삼항연산자로 많은 난관을 구현했으며 그래서 삼항 연산자를 전보다는 조금 다룰 수 있게 된 것 같아.
  • 기능을 배움에 있어 알고만 있고 쓰지 못하면 그건 알고 있는게 아니다라는 생각을 절실히 하게 되었다.
  • (사실 여기서의 리팩토링은 내가 한게 아니라 내 선임분이 했다..)
  • 하나하나 뜯어보자면
    • placeholderText는 말그대로 선택하기 전에 적혀있는 힌트문구 이고
    • selected는 선택하면 나오는 날짜이다.
    • 즉, onChange에 있는 setStartDate를 통해 startDate를 지정하게 되고 이게 반영되는 것이다.
    • dateFormat은 시간 포멧을 변경하는것이다. (지금 적으면서 본거지만 이걸 잘 활용해서 진행했다면 후반에 date 객체의 포멧때문에 삽질하는 시간을 줄일 수 있지 않았을까 싶다..)
    • minDate, startDate, endDate는 각각
      • 과거를 선택하지 못하게 할때 과거의 기준
      • 달력에서 범위를 지정할 때 시작점
      • 달력에서 범위를 지정할 때 끝점 이다.
    • 이벤트를 등록할때는 당일만 등록하도록 기획이 되어 있기에 지금은 endDate를 알 수가 없지만 흔히들 경험한 비행기 왕복 날짜를 정할때 그 범위가 시작 날짜에도 보이게 해주는 그 기능이다.
    • ref는 useRef를 이용해서 datepicker를 가공할 수 있도록 도와주는데 나의 경우는 만들기만 하고 쓰지는 않았다
    • onBlur는 과거 회원가입을 만들때 유용 했던 그 기능으로 입력하지 않고 넘어갔을 때 에러메시지를 띄우게 하는 것 이지만 여기서는 쓰이지 않았다.
  • 그리고 중요했던 속성이 하나 있는데 바로 customInput과 그 안의 forwardRef이다.
    • customInput속성은 하나의 컴포넌트를 그 값으로 받는데
    • 속성의 이름과 같이 input창을 커스텀 할 수 있게 된다.
    • 이때 forwardRef가 쓰이게 되는데 자세한 forwardRef에 대한 자세한 내용은
    • https://www.daleseo.com/react-forward-ref/
    • 여기가 잘 설명했으니 참고하고
    • datepicker에서는 customInput 안에 쓰이는 값에 value와 onClick이 이미 정의되어 있기 때문에
    const ExampleCustomInput = forwardRef(({ value, onClick }, ref) => (
        <DateButton
          onClick={onClick}
          ref={ref}
          color={value.length === 0 ? "#b3b3b3" : "black"}
        >
          {value.length === 0 ? "YYYY.MM.DD" : value}
        </DateButton>
      ));
    
    /////
    const DateButton = styled.div`
      width: 384px;
      border-radius: 10px;
      border: 2px solid #e4e4e4;
      background-color: #ffffff;
      padding-left: 20px;
      height: 36px;
    
      font-family: "Noto Sans KR";
      font-style: normal;
      font-weight: 300;
      font-size: 16px;
      line-height: 36px;
      letter-spacing: -0.04em;
      /* color: black; */
      color: ${props => props.color};
    `;
    
    • 나는 이런식으로 응용했다.
    • 이렇게 하면 손쉽게 datepicker의 input창을 custom할 수 있다.
    • 참고로 color는 value의 length를 이용해서 placeholder를 구현했다.
      • 이제보니까 엉망이다.. 위에서의 placeholderText를 지워도 이 코드 때문에 전혀 문제 되지 않는다.
      • 당연하다면 당연한게 이 customInput을 통해 위의 placeholderText가 덮어지기 때문이다.