๐Ÿ’ป Programming/React

[React] react-datepicker ๋‹ฌ๋ ฅ ์™ธ๋ถ€ ํด๋ฆญ์‹œ ์ด๋ฒคํŠธ ์ „๋‹ฌ ๋ง‰๋Š” ๋ฐฉ๋ฒ•

najiwon 2024. 7. 13. 15:10

 

01. ๋ฌธ์ œ

2์ผ๋™์•ˆ ์ฐพ์•„๋ณด๋˜ ๋ฒ„๊ทธ…

 

ํšŒ์‚ฌ ํ”„๋กœ์ ํŠธ์—์„œ react-datepicker๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋‹ฌ๋ ฅ์„ ๋งŒ๋“ค์—ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๋‹ฌ๋ ฅ์„ ๋‹ซ์œผ๋ ค๊ณ  ๋ฐฐ๊ฒฝ์„ ํด๋ฆญํ–ˆ์„ ๋•Œ, ๋‹ฌ๋ ฅ์ด ๋‹ซํžˆ๊ณ  ์ด๋ฒคํŠธ๊ฐ€ ์ข…๋ฃŒ๋˜์–ด์•ผ ํ•˜๋Š”๋ฐ. ํด๋ฆญํ•œ ์œ„์น˜์— ๋ฒ„ํŠผ์ด๋‚˜ ์–ด๋–ค ์ด๋ฒคํŠธ๊ฐ€ ๋‹ฌ๋ฆฐ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์žˆ์œผ๋ฉด ๊ทธ ์ด๋ฒคํŠธ๊ฐ€ ์‹คํ–‰๋˜์—ˆ๋‹ค.

 

๋ฆฌ์•กํŠธ ๊ฐ•์˜๋ฅผ ๋“ค์œผ๋ฉฐ ์‹ค์Šตํ•˜๊ณ  ์žˆ๋˜ ํ”„๋กœ์ ํŠธ๋ฅผ ์—ฐ์Šต์žฅ ์‚ผ์•„ ๋‹ฌ๋ ฅ์„ ๋‹ค์‹œ ๋งŒ๋“ค์–ด๋ดค๋‹ค. ๋‹ฌ๋ ฅ ์™ธ๋ถ€์— ์ฃผ๋ฌธํ•˜๊ธฐ ๋ฒ„ํŠผ์„ ํด๋ฆญํ–ˆ์„ ๋•Œ ๋ฒ„ํŠผ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜์˜€๋‹ค. 

 

ProductItem์— ์žˆ๋Š” ๋ฒ„ํŠผ ์ด๋ฒคํŠธ๊ฐ€ ์‹คํ–‰๋˜๋Š” ๊ฒƒ์„ ๋กœ๊ทธ๋ฅผ ํ†ตํ•ด ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

 

02. ํ•ด๊ฒฐ๊ณผ์ •

DatePicker์— ์žˆ๋Š” onClickOutside์— ๋ฒ„๋ธ”๋ง์„ ์ค‘๋‹จํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ๋„ฃ์–ด์คฌ๋‹ค. -> (X) ํ•ด๊ฒฐ๋˜์ง€ ์•Š์Œ

    <CalendarWrapper>
      {/* {isOpen && <Overlay id="wldnjs" onClick={handleOverlayClick} />} */}
      <DatePicker
        selected={startDate}
        onChange={(date) => {
          console.log("111");
          setStartDate(date);
          setIsOpen(false);
        }}
        onCalendarOpen={() => {
          console.log("222");
        }}
        onCalendarClose={() => {
          console.log("333");
          setIsOpen(false);
        }}
        onClickOutside={(e) => {
          console.log("444");
          e.stopPropagation();
        }}
        withPortal
      />
    </CalendarWrapper>

 

DOM์š”์†Œ์— ์ง์ ‘ ์ ‘๊ทผํ•˜์—ฌ CalendarWrapper ๋‚ด๋ถ€์— event.target์ด ํฌํ•จ๋˜์–ด ์žˆ์ง€ ์•Š๋Š” ๊ฒฝ์šฐ event.stopPropagation(); ์œผ๋กœ ๋ฒ„๋ธ”๋ง์„ ์ค‘๋‹จํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ๋„ฃ์–ด์คฌ๋‹ค. -> (X) ํ•ด๊ฒฐ๋˜์ง€ ์•Š์Œ

  const calendarRef = useRef(null);
  
  useEffect(() => {
    const handleClickOutside = (event) => {
      console.log("handleClickOutside");
      console.log(calendarRef.current);
      console.log(event.target);

      if (calendarRef.current && !calendarRef.current.contains(event.target)) {
        console.log(calendarRef.current.contains(event.target));
        event.stopPropagation();
        event.preventDefault();
        setIsOpen(false);
      }
    };

    document.addEventListener("mousedown", handleClickOutside);
    return () => {
      document.removeEventListener("mousedown", handleClickOutside);
    };
  }, [calendarRef]);
  
    <CalendarWrapper ref={calendarRef}>
      <DatePicker
        selected={startDate}
        onChange={(date) => {
          console.log("111");
          setStartDate(date);
          setIsOpen(false);
        }}
        onCalendarOpen={() => {
          console.log("222");
        }}
        onCalendarClose={() => {
          console.log("333");
          setIsOpen(false);
        }}
        onClickOutside={(e) => {
          console.log("444");
        }}
        withPortal
      />
    </CalendarWrapper>
  

 

03. ํ•ด๊ฒฐ

react-datepicker ๊นƒ ๋ ˆํฌ์ง€ํ† ๋ฆฌ์—์„œ ํ•œ๋ฒˆ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด์„œ ์›์ธ์„ ์ฐพ์•„๋ณด๊ธฐ๋กœ ํ–ˆ๋‹ค.

Issues ํƒญ์ด ์žˆ๊ธธ๋ž˜ ์ด๋Ÿฐ ๋ฌธ์ œ๊ฐ€ ๋‚˜๋งŒ ๋ฐœ์ƒํ•˜๋Š”๊ฑด๊ฐ€ ์‹ถ์–ด์„œ ๊ฒ€์ƒ‰์„ ํ•ด๋ดค๋”๋‹ˆ ๊ฐ™์€ ๋ฌธ์ œ์— ๋Œ€ํ•œ ๋‚ด์šฉ์ด ์˜ฌ๋ผ์™€ ์žˆ์—ˆ๋‹ค. !!

 

https://github.com/Hacker0x01/react-datepicker/issues/2524

์—ฌ๊ธฐ์— ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์ด ์žˆ์—ˆ๋‹ค. !!! ์—‰์—‰ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค..

 

document.addEventListener("touchstart", handelTouchStart, true);๋กœ touchstart ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•  ๊ฒฝ์šฐe.stopPropagation();์œผ๋กœ ์ด๋ฒคํŠธ ๋ฒ„๋ธ”๋ง์„ ์ค‘๋‹จํ•  ์ˆ˜ ์žˆ๋„๋ก ํ–ˆ๋‹ค.

๋‹ฌ๋ ฅ์ด ๋‹ซํžˆ๋ฉด ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๋ฅผ ์ œ๊ฑฐํ•œ๋‹ค. ๋‹ฌ๋ ฅ์„ ๋‹ซ์„ ๋•Œ ๋ฆฌ์Šค๋„ˆ๊ฐ€ ์ œ๊ฑฐ๋˜์ง€ ์•Š์•„ ์›์น˜ ์•Š๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๋‹ค์‹œ ๋ Œ๋”๋งํ•  ๋•Œ ํ•จ์ˆ˜๋ฅผ ์žฌ์ •์˜ํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด removeEventListener๋กœ ์ด๋ฒคํŠธ๋ฆฌ์Šค๋„ˆ๋ฅผ ์ œ๊ฑฐํ•ด์คฌ๋‹ค.

const Calendar = () => {
  const [startDate, setStartDate] = useState(new Date());

  const handelTouchStart = useCallback((e) => e.stopPropagation(), []);

  const hadleCalendarOpen = () => {
    console.log("open");
    document.addEventListener("touchstart", handelTouchStart, true);
  };

  const hadleCalendarClose = () => {
    console.log("close");
    document.removeEventListener("touchstart", handelTouchStart, true);
  };

  return (
    <CalendarWrapper>
      <DatePicker
        selected={startDate}
        onChange={(date) => {
          setStartDate(date);
        }}
        onCalendarOpen={hadleCalendarOpen}
        onCalendarClose={hadleCalendarClose}
        withPortal
      />
    </CalendarWrapper>
  );
};

 

๋”์ด์ƒ ๋ฒ„ํŠผ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. !!