본문 바로가기

react

react-date-range with useRef

결과물은 이렇다 !

달력 컴포넌트외부를 어둡게 처리하고, 어두운 부분 클릭시 달력이 닫히게 구현하고 싶었다.

🎂 install

$ yarn add react-date-range

🎂 code

export const DatePicker = ({
  calendarCloseHandler,
  dateRange,
  setDateRange,
}: {
  calendarCloseHandler: (range: Range) => void;
  dateRange: Range;
  setDateRange: (range: Range) => void;
}) => {
  const ref = useRef<HTMLDivElement>(null);
  const [isShowCalendar, setIsShowCalendar] = useState<boolean>(false);
  const [focusedDateRange, setFocusedDateRange] = useState<[number, number]>([0, 0]);

  const IsShowCalendarHandler = (range: Range) => {
    if (focusedDateRange[1] === 1) {
      calendarCloseHandler(range);
      setIsShowCalendar(false);
    }
  };
  const checkIfClickedOutside = (e: MouseEvent) => {
    if (ref.current && !ref.current.contains(e.target as Node)) {
      setIsShowCalendar(false);
    }
  };

  useEffect(() => {
    if (!i18n.isInitialized) return;
  }, [i18n.isInitialized]);

  useEffect(() => {
    document.addEventListener("mousedown", checkIfClickedOutside);

    return () => {
      // Cleanup the event listener
      document.removeEventListener("mousedown", checkIfClickedOutside);
    };
  }, [isShowCalendar]);

  return (
    <div className="mState typeDate">
      <div style={{ position: "relative" }}>
        <div className="mDateRangePicker" onClick={() => setIsShowCalendar(true)}>
          {dayjs(dateRange.startDate).format("YYYY-MM-DD")} ~ {dayjs(dateRange.endDate).format("YYYY-MM-DD")}
        </div>
      </div>
      <div className={isShowCalendar ? "mDateRangeModal" : ""}>
        {isShowCalendar && (
          <div ref={ref} className="mDateRangeModal2">
            <DateRange
              // @ts-ignore
              locale={i18n.language.substr(0, 2) in dateFnsLocales ? dateFnsLocales[i18n.language.substr(0, 2)] : dateFnsLocales["enUS"]}
              months={1}
              onChange={async (range) => {
                setDateRange(range.selection);
                IsShowCalendarHandler(range.selection);
              }}
              focusedRange={focusedDateRange}
              onRangeFocusChange={setFocusedDateRange}
              showDateDisplay={false}
              ranges={[dateRange]}
              minDate={subDays(new Date(), 365)}
              maxDate={subDays(new Date(), 1)}
            />
          </div>
        )}
      </div>
    </div>
  );
};

setIsShowCalendar state를 통해 달력 컴포넌트를 출력할 지 결정한다.

상위 props인 dateRange, setDateRange 를 통해 달력 컴포넌트에서 클릭 이벤트가 발생할 시, 상위 컴포넌트로 선택한 날짜를 전달한다.

🎂 뒷 부분 어둡게 하기

이건 css 로 처리했음 !
react-date-range 에서 제공하는 DateRange 컴포넌트 상위 > 상위 div 에(나의 경우 mDateRangeModal) background 값으로 rgba(0, 0, 0, 0.7)를 적용했다.
그 밖에 가운데 정렬 등등은 다음으로 처리 !

.mDateRangeModal {
    display: flex;
    position: fixed;
    top: 0px;
    left: 0px;
    right: 0px;
    z-index: 102;
    height: 100%;
    align-items: center;
    background: rgba(0, 0, 0, 0.7);
}

.mDateRangeModal2 {
    max-width: calc(100% - 32px);
    margin: 0 auto;
}

🎂 close when outside onClick

  const ref = useRef<HTMLDivElement>(null);


  const checkIfClickedOutside = (e: MouseEvent) => {
    if (ref.current && !ref.current.contains(e.target as Node)) {
      setIsShowCalendar(false);
    }
  };


  useEffect(() => {
    document.addEventListener("mousedown", checkIfClickedOutside);

    return () => {
      // Cleanup the event listener
      document.removeEventListener("mousedown", checkIfClickedOutside);
    };
  }, [isShowCalendar]);

DateRange 컴포넌트에 ref를 줘도 되는데, 큰 이유 없이 한단계 상위 div를 dif 로 잡았다. (ts 때문이였나 ?)

checkIfClickedOutside 를 통해 ref 이외의 곳을 클릭할 경우 캘린더를 닫으며, useEffect 를 통해 해당 이벤트를 주입시킨다.

 

 

반응형

'react' 카테고리의 다른 글

emotion in next.js + typescript  (1) 2022.05.06
nextjs deployment with 644 permission  (0) 2022.01.01
react-i18next in next.js  (0) 2021.10.11
useContext in navigation bar  (0) 2021.10.09
jsx switch  (0) 2021.09.06