[React] click/keydown 이벤트 등으로 인해 blur 이벤트 발생시, click/keydown 이벤트가 씹히는(무시되는) 케이스에 대한 해결

By | 3월 23, 2023

개요

  • focus 라는 이름의 boolean state를 특정 input의 focus 여부에 따라 상태관리를 하려 함.
  • input의 onBlur(), onFocus() 에서 set state를 하는데, click/keydown 등으로 촉발(trigger)된 Blur이벤트를 타서 set state를 할 경우, 원래의 이벤트인 click/keydown이 실행되지 않는 문제 발견
  • onBlur() 에서 set state를 할 경우, 리렌더링이 발생하고 최초 이벤트가 무시되는 것처럼 보임.
  • 처음에는 event.relatedTarget 을 통해 해결하려 했으나, click은 해결이 되지만, keydown은 해결되지 않는 문제가 있었음
  • onBlur/onFocus 핸들러가 아닌, input ref와 document.activeElment 를 사용하여 해결함.


소스 조각

const inputRef = useRef<HTMLInputElement>(null); // 입력폼 ref
const [focus, setFocus] = useState<boolean>(false); // 입력폼에 포커스가 있는지의 여부
...
  /**
   * 최초, focus state 에 대한 상태관리를 input element의 onFocus/onBlur handler에 위임했었으나, 아래와 같은 문제들이 있었다.
   *
   *  1. 다른 element를 click 했을 때, input > onBlur가 호출되는데, 이 때 blur를 촉발한 click 이벤트가 무시되어 버린다.
   *    - 검색해 보니 click 대신 mousedown을 사용하면 된다고 하는데, click - mousedown은 작동방식이 다른 이벤트이므로 이 우회책은 권장하지 않는다고 한다.
   *    - onBlur 호출시 이벤트객체.relatedTarget 속성을 사용하여 click 기능을 커버할 수 있었다.
   *      - (e.relatedTarget as any)?.click?.();
   *
   *  2. click event는 위와 같은 작업으로 우회할 수 있었으나, input 에 걸린 또 다른 이벤트인 keydown 의 경우는 우회책을 발견할 수 없었다.
   *    (방향키 아래를 눌러서 자동완성 목록으로 커서 이동하는 요건)
   *
   *  3. 결국 onBlur / onFocus 이벤트핸들러가 아닌 다른 방법으로 focus state 에 대한 상태 관리를 해야만 했고, 검색을 통해 이 방법을 찾을 수 있었다.
   */
  if (document.activeElement == (inputRef as any)?.current) {
    // too many re-renders 방지용 if 문
    if (!focus) {
      setFocus(true);
    }
  } else {
    if (focus) {
      setFocus(false);
    }
  }


기타

  • 현재 엘리먼트에 포커스가 있는지의 여부를 ref를 통해 확인하는 방법임.
  • 동적으로 행이 추가되는 UI에 컴포넌트가 속해 있다면 정상 동작하지 않을 수 있다. (추가적인 실험 필요)


참고

Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments