My-world 개발 보고서 : 모달창 커스텀 훅으로 관리하기, useRef의 타입

강원지·2023년 4월 26일
0

모달창 커스텀 훅으로 관리하기

윈도우 디자인을 모토로 하기 때문에 모달을 자주 활용할 것 같아 모달 외부 클릭 시 자동으로 창을 닫히게 하는 기능을 훅으로 만들어 관리하고자 한다.

useEffect의 dependency를 outsideRef로 지정해주었다. outsideRef는 모달의 외부 영역의 DOM을 다룬다. 모달 외부 영역을 활성화하고 클릭하면 ref가 current: div로 바뀌고 다시 클릭하면 current: null이 된다.

useEffect(() => {
    const listener: listenerType = (e) => {
      if (e.target !== outsideRef.current) return;
      //클릭한 요소와 모달 외부 영역이 일치한다면 handler을 수행함.
      //여기서는 dispatch(closeModal())에 해당함.
      handler(e);
    };
    document.addEventListener("mousedown", listener);
    return () => {
      document.removeEventListener("mousedown", listener);
      //이벤트 종료
    };
  }, [outsideRef]);

전체 코드

useModal.ts

import { useEffect, RefObject } from "react";

type listenerType = (this: Document, ev: MouseEvent) => void;
type useModalType = (
  outsideRef: RefObject<HTMLDivElement>,
  handler: (event: MouseEvent) => void
) => void;

export const useModal: useModalType = (outsideRef, handler) => {
  useEffect(() => {
    const listener: listenerType = (e) => {
      if (e.target !== outsideRef.current) return;
      handler(e);
    };
    document.addEventListener("mousedown", listener);
    return () => {
      document.removeEventListener("mousedown", listener);
    };
  }, [outsideRef]);
};

사용법

  useModal(모달을 감싸는 div의 ref, () => 클릭 시 실행될 함수);

기존 코드

useRef의 타입

에러 발생

'HTMLDivElement' 형식에 'current' 속성이 없습니다
아래 코드에 에러가 발생했다.

type useModalType = (outsideRef: HTMLDivElement, handler: any) => void;
if (e.target !== outsideRef.current) return;//에러발생

outsideRef는 state 자체가 아니라 current를 다루는 'useRef'이기 때문에 HTMLDivElement으로만 단순히 타입을 지정해서는 안되고 HTMLDivElement을 useRef의 객체 타입의 제네릭 값으로 넘겨줘야 한다.

useRef의 객체 타입

MutableRefObject : current 변경 가능

  interface MutableRefObject<T> {
      current: T;
  }

RefObject : current에 대해 readonly만 가능

  interface RefObject<T> {
      readonly current: T | null;
  }

적용

useModal.ts

type useModalType = (
  outsideRef: RefObject<HTMLDivElement>,
  handler: (event: MouseEvent) => void
) => void;

square.ts
outside의 추론 타입도 React.MutableRefObject로 바꿔주었다.

 const outside = useRef() as React.MutableRefObject<HTMLDivElement>;

참고
https://driip.me/7126d5d5-1937-44a8-98ed-f9065a7c35b5

넣을 만한 기능

메모장 테마 분리 - text, 코드 블럭, todo

0개의 댓글