onKeydown event는 기본 event가 없다.

조용환·2024년 4월 4일
0

troubleShooting

목록 보기
1/1

모달에서 onKeydown 이벤트를 설정할 일이 있었다.
처음에는 onKeyDown에 submit처럼 기본이벤트가 있을거라 생각해서 커스텀모달을 만들때 onKeydown 이벤트에 event.preventDefault()를 걸어주었는데, 이를 모달 내부에 추가되는 input창에서 입력시 외부 onKeydown이벤트가 이벤트 버블링에 의해 실행되기 때문에 event.stopPropagation()을 써줘야하는 문제가 있었다.
하지만 기본 이벤트가 없기 때문에 event.preventDefault() 및 event.stopPropagation()이 필요없다는 것을 깨닫고 삭제 해주어 코드를 간편하게 만들어주었다.

// components/modalCustom.tsx
"use client";
import React, {
  Fragment,
  KeyboardEvent,
  ReactNode,
  useEffect,
  useState,
} from "react";
import ReactDOM from "react-dom";
import { ModalCustomProps } from "@/type/interface";

// name: 필수
export default function ModalCustom({
  name,
  buttonString = { cancel: "취소하기", add: "등록하기" },
  design = "",
  changeButton = false,
  open,
  onClose,
  onClickEvent,
  children,
}: ModalCustomProps) {
  const [prevScrollY, setPrevScrollY] = useState<number | undefined>(undefined);
  const [hasScrollbar, setHasScrollbar] = useState<boolean>(false);
  // 스크롤이 있는지 확인하는 함수
  const checkScrollbar = (): void => {
    setHasScrollbar(document.body.scrollHeight > window.innerHeight);
  };

  const keyDownHandler = (event: KeyboardEvent<HTMLInputElement>) => {
    if (!open) {
      return;
    }
    //event.preventDefault(); 
    // 이것을 막음으로써 이벤트 버블링이 일어나 디버깅에 시간이 소요되었다.
    if (event.key === "Enter") {
      document.getElementById(`${name}AddButton`)?.click();
    } else if (event.key === "Escape") {
      document.getElementById(`${name}CancelButton`)?.click();
    }
  };

  useEffect((): void => {
    checkScrollbar();
    // 스크롤을 방지하고 현재 위치를 반환
    const preventScroll = (): void => {
      const currentScrollY = window.scrollY;
      document.body.style.position = "fixed";
      document.body.style.width = "100%";
      document.body.style.top = `-${currentScrollY}px`; // 현재 스크롤 위치
      document.body.style.overflowY = hasScrollbar ? "scroll" : "hidden";
      setPrevScrollY(currentScrollY);
    };

    // 스크롤을 허용하고, 스크롤 방지 함수에서 반환된 위치로 이동
    const allowScroll = (): void => {
      document.body.style.position = "";
      document.body.style.width = "";
      document.body.style.top = "";
      document.body.style.overflowY = "";
      if (prevScrollY !== undefined) {
        window.scrollTo(0, prevScrollY);
      }
    };
    // 모달이 열릴 때마다 스크롤바 여부를 확인하고, 스크롤 방지/허용 함수 호출
    if (open) {
      checkScrollbar();
      preventScroll();
    } else {
      allowScroll();
    }
  }, [open, hasScrollbar, prevScrollY]);

  if (!open) return null;

  return ReactDOM.createPortal(
    <Fragment>
      <div
        className="fixed top-0 bottom-0 left-0 right-0 z-50 bg-black bg-opacity-40"
        onClick={onClose}
      />
      <div
        tabIndex={0}
        onKeyDown={keyDownHandler}
        className={`fixed z-50 px-20 py-12 transform -translate-x-1/2 -translate-y-1/2 bg-white top-1/2 left-1/2 rounded-xl outline-none ${design}`}
      >
        {children}
        <div className="flex justify-center mt-5 ">
          <button
            id={`${name}CancelButton`}
            onClick={onClose}
            className={`px-12 py-2 mr-6 text-sm font-semibold rounded-md text-neutral-100  ring-1 ring-inset ring-f5red-700/10 ${changeButton ? "bg-f5green-350 hover:bg-f5green-300" : "bg-f5red-350 hover:bg-f5red-300"}`}
          >
            {buttonString.cancel}
          </button>
          <button
            id={`${name}AddButton`}
            onClick={async () => {
              if (await onClickEvent()) {
                onClose();
              }
            }}
            type="button"
            className={`px-12 py-2 text-sm font-semibold rounded-md text-neutral-100  ring-1 ring-inset ring-f5green-700/10 ${changeButton ? "bg-f5red-350 hover:bg-f5red-300" : "bg-f5green-350 hover:bg-f5green-300"}`}
          >
            {buttonString.add}
          </button>
        </div>
      </div>
    </Fragment>,
    document.getElementById("globalModal") as HTMLElement
  );
}
// myEssay.tsx
const handleKeyDown = (
    e: React.KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>
  ) => {
    if (e.key !== "Enter" && e.key !== "Escape") {
       e.stopPropagation();
    }
 }; // 불필요한 함수


//그외
<ModalCustom
        open={isEssayChangeModalOpen}
        name="changeEssay"
        onClose={() => setIsEssayChangeModalOpen(false)}
        onClickEvent={changeEssay}
        buttonString={{ cancel: "취소하기", add: "변경하기" }}
      >
        <div className="flex flex-col h-min-[800px] text-xl font-medium ">
          <span className="text-center">🖋 자소서 변경하기 🖋</span>
          <label htmlFor="inputTitle" className="font-bold">
            자기소개서 항목
          </label>
          <input
            type="text"
            placeholder="빌 경우 원래 항목이 들어갑니다"
            className="w-[700px] min-h-16 p-1 h-auto text-sm focus:outline-f5green-300 my-3 "
            ref={essayTitleChangeRef}
            id="inputTitle"
            onKeyDown={(e) => handleKeyDown(e)}
            // 이 onKeyDown 처리는 필요 없는 것이였다.
          />
          <label htmlFor="inputEssay" className="font-bold ">
            자기소개서 내용
          </label>
          <textarea
            placeholder="빌 경우 원래 내용이 들어갑니다."
            className="w-[700px] max-w-[100%] p-1 h-auto mt-3 min-h-40 text-sm my-3 focus:outline-f5green-300 text-start"
            ref={essayChangeRef}
            id="inputEssay"
          />
        </div>
      </ModalCustom>
profile
practice react, javascript

0개의 댓글