본문 바로가기
제니의 개발일지/도움이 되었던 것 정리

[TypeScript] useRef 모달 바깥 영역 클릭 이벤트

by 제니운 2023. 3. 27.
728x90

 

오랜만의 블로그 포스팅

매일 회사에서 코딩을 하면서 정신없는 시간을 보내다 보니 정리를 못했는데, 시간 날 때마다 유용하게 써먹었던 코드를 정리하기는 해야겠다.

 

 

반복적으로 쓰이는 코드들은 다시 내 코드를 찾아보는 경우가 많은데 몇 달사이에 그나마 코드 리팩토링을 하게 되는 나를 보면서 아주 조금의 배움과 반성을 함께 하는 중!! 

옆에 사수님이 계셔서 정말 감사하고 도움이 많이 된다.

 

 

그 동안, 모달 바깥 영역을 구현했던 방식은 useState로 open이면 true가 되고 이런식의 코드였는데 그렇게 되면 발생되는 문제는

 

 

❗ 영역 바깥을 클릭했을 땐 꺼지지 않을 수 있다는 것!

 

 

물론, position fixed를 해서 모달을 띄운다거나 할 경우엔, 여러 가지 방법을 통해서 모달을 끌 수는 있지만 번거롭다. 그래서 찾아보다 요즘 유용하게 쓰는 방법을 정리해 보았다.

 

 

1️⃣ useState로 boolean 값 정해놓기 + useRef 설정하기

 

🔹 useRef는 버튼을 클릭할 곳의 영역에 만들어주면 된다.

 

  const [isShowOptions, setIsShowOptions] = useState<boolean>(false);
  
  const modalRef = useRef<HTMLDivElement>(null);

 

 

2️⃣ 함수 정의

 

const onClickMenuOpen = useCallback(() => {
    if (isShowOptions === false){
      setIsShowOptions((prev) => !prev);
    } else {
      setIsShowOptions(false);
    }
}, [isShowOpen]);


const hideOptions = useCallback((e:MouseEvent) => {
    if (modalRef.current === null) {
      return;
    }
    if (!modalRef.current.contains(e.target as HTMLElement)) {
      setIsShowOptions(false);
    }
}, []);


useEffect(() => {
    document.addEventListener('click', hideOptions, true);
    return () => {
      document.removeEventListener('click', hideOptions, true);
    };
}, [hideOptions, isShowOptions]);

 

 

🔹 modalRef의 영역을 포함하지 않을 경우, 즉 바깥 영역을 클릭하게 되면 false가 되라고 코드를 작성한 것이다.

 

3️⃣ 사용할 곳의 코드

 

<div>
   <Title 
    isShowOptions={isShowOptions} // css 설정하면 된다.
    ref={modalRef}
    onClick={onClickMenuOpen}
    >제목</Title>    
    <Menu isShowOptions={isShowOptions}> // css 설정하면 된다.
        <MenuContents>코드 참고</MenuContents>
    </Menu>
</div>

 

 

4️⃣ styled-component 설정

 

 

interface MenuProps{
   isShowOptions: boolean;
}

const Menu = styled.div<MenuProps>`
    visibility: ${({ isShowOptions }) => (isShowOptions ? 'visible' : 'hidden')};
    opacity: ${({ isShowOptions }) => (isShowOptions ? '1' : '0')};
`

 

🔹 위 처럼, visibility, opacity는 설정해주면 되고 나머지 css는 디자인에 맞춰서 수정하면 된다.

 

 

더 좋은 방법들도 많이 있을 것이다.

지금은 정리하는 코드를 여러 방면에 쓰고 있어서 기록해보았다.

 

 

 

728x90