[Custom] useLongClick

이짜젠·2021년 8월 19일
0

리액트에서 엘리먼트를 꾹 눌렀을때에 대한 이벤트처리가 필요했다.
그래서 만든 customHook이다.

공통로직을 hook으로 뺴면서 event처리를 react외부에서 처리했다는 점에서 안티패턴인 것 같긴하다..
하지만 마땅히 좋은방법이 떠오르지 않았다.. ㅠㅠ

코드

import { useState, useRef, useEffect, useLayoutEffect } from 'react';

const inEvents = ['touchstart', 'mousedown'];
const outEvents = ['touchcancel', 'click', 'touchend', 'mouseout'];

function useLongClick(targetEl: HTMLElement | null, delayMs: number | undefined = 400) {
  const pressTimer = useRef<any>(null);
  const [longClicked, setLongClicked] = useState<boolean>(false);

  useLayoutEffect(() => {
    if (targetEl) {
      inEvents.forEach(eventNm => targetEl?.addEventListener(eventNm, touchStart));
      outEvents.forEach(eventNm => targetEl?.addEventListener(eventNm, touchEnd));
    }

    return () => {
      if (targetEl) {
        inEvents.forEach(eventNm => targetEl?.removeEventListener(eventNm, touchStart));
        outEvents.forEach(eventNm => targetEl?.removeEventListener(eventNm, touchEnd));
      }
    };
  }, [targetEl]);

  const touchStart = () => {
    if (!pressTimer.current) {
      pressTimer.current = setTimeout(() => {
        if (pressTimer) {
          setLongClicked(true);
        }
      }, delayMs);
    }
  };

  const touchEnd = () => {
    if (pressTimer.current) {
      clearTimeout(pressTimer.current);
      pressTimer.current = null;
      setLongClicked(false);
    }
  };

  return {
    event: longClicked,
  };
}

export default useLongClick;

사용예시

function Button() {
  const msgRef = useRef<any>(null);
  const [msgEl, setMsgEl] = useState<HTMLElement | null>(msgRef.current);
  const longClick = useLongClick(msgEl);  
  /*
  msgRef.current를 useLongClick에 파라미터로 집어넣으면 msgRef의 초기값이 null로 넘어가게된다. 
  따라서 state를 넘기고 msgRef에 DOM이 세팅되는 시점에 state에 msgRef.current를 세팅해주는 방식으로 작업해야한다.
  */
  

  useLayoutEffect(() => {
    setMsgEl(msgRef.current);
  }, []);
  
  useEffect(() => {
    console.log('fired longClick!!!');
  }, [longClick.event])
  
  return (
    <Button>
    	<span ref={msgRef}>메세지</span>
    </Button>
  )
}
profile
오늘 먹은 음식도 기억이 안납니다. 그래서 모든걸 기록합니다.

0개의 댓글