Input focus와 absolute 버튼

JN·2024년 3월 31일
post-thumbnail

위와 같은 X 버튼이 달린 공통 Input 컴포넌트를 개발하였다.

X 버튼의 기능 명세는 다음과 같다.

  1. Input이 포커스 될 때에만 X 버튼이 나타나야 한다.
  2. X 버튼을 클릭하면 Input에 입력되어 있던 값이 초기화 되어야 한다.

1번 기능을 위해 다음과 같이 간단하게 구현했다

.cm-input:focus + .x-btn {
  display: block;
}

음~ 예상대로 Input이 focus 될 경우 X 버튼아 잘 나타났고, blur 될 경우에 잘 사라졌기 때문에 1번을 완료했다.

하지만 문제는 2번이었다.
X 버튼이 onClick 이벤트가 발생하지 않았다.

문제의 코드를 보자.


  const inputRef = useRef<HTMLInputElement>(null);
  const [focused, setForcused] = useState(false);
  const clearInput = () => {
    setValue("");
  };

 const handleBlur = () => {
 	setForcused(false);
  };


// tsx
//....
	<input value={value ? value : ""}
    onFocus={() => setForcused(true)}
    onChange={(e) => setValue(e.target.value)}
    ref={inputRef}
    placeholder={placeholder}
/>

{focused && (
  <div
    className=" z-30 x-btn absolute top-[50%] translate-y-[-50%] cursor-pointer right-[10px]"
    onClick={clearInput}
    >
    <Image
      alt="x"
      src={"/images/icons/x.svg"}
      height={24}
      width={24}
      />
  </div>
)}

문제가 보이는가?
clearInput 콜백 함수가 작동하지 않는 이유 말이다.
이유는 X 버튼이 Input 요소 위에 absolute로 있었기 때문에
X 버튼 클릭시 엄연히 Input가 Blur 될 수 있는 영역이었기 때문이다.
쉽게 말해서 눈으로 봤을 때 같은 영역 안에 있다고 진짜 같은 부분에 있는 것이 아니라고 이해했다.
그래서 X 버튼을 클릭했을때 X버튼의 onClick 함수보다 handleBlur 함수가 더 먼저 실행되어 focused가 false 이므로 버튼이 먼저 사라지게 된다.

그래서 블러 이벤트 처리를 지연시키는 방법으로 다음과 같이 해결할 수 있었다.


  const inputRef = useRef<HTMLInputElement>(null);
  const [focused, setForcused] = useState(false);
  const clearInput = () => {
    setValue("");
  };

  const handleBlur = () => {
    setTimeout(() => {
      setForcused(false);
    }, 10); 
  };

// tsx
//....

<input value={value ? value : ""}
    onFocus={() => setForcused(true)}
    onBlur={handleBlur}
    onChange={(e) => setValue(e.target.value)}
    ref={inputRef}
    placeholder={placeholder}
/>

{focused && (
  <div
    className=" z-30 x-btn absolute top-[50%] translate-y-[-50%] cursor-pointer right-[10px]"
    onClick={clearInput}
    >
    <Image
      alt="x"
      src={"/images/icons/x.svg"}
      height={24}
      width={24}
      />
  </div>
)}
profile
개발일지📒

0개의 댓글