[React]리액트 훅, 외부클릭 감지 모달창 구현

2021. 4. 18. 19:48Web_Programming/React

안녕하세요. 이번 포스팅에서는 진행 중인 트위터 클론 코딩 프로젝트에서 모달 창을 구현하다 애를 먹었던 게 너무 아까워서 구현 방법을 작성해보려 해요 👊

저는 모달창을 구현하기 전에 details태그를 이용하여 서브 메뉴들을 작성했는데 다시 해당 태그를 클릭해야지만 메뉴가 닫히는 게 꼴 보기 싫더라고요..ㅎ

그래서 이것저것 알아봤는데 이렇게 특정 영역 외의 부분을 클릭하면 창이 닫히는 것을 모달 창이라고 하더라고요

react에서 modal라이브러리가 있기는 한데.. 제가 원하는 느낌은 아니라 제가 구현하는 쪽으로 선택했어요


모달 창을 위한 컴포넌트를 만들어서 코드를 작성했고, 구현 페이지에서 컴포넌트를 불러와서 작성했습니다.

먼저 구현된 화면을 보여드릴게요.

 


Modal.js파일을 생성하여 컴포넌트 코드를 작성하였습니다.

import React, {  useEffect, useRef } from 'react';
const Modal =({isOpenModal, setIsOpenModal, children})=> {
  const wrapperRef = useRef();
  useEffect(()=>{
    document.addEventListener('mousedown', handleClickOutside);

    return()=>{
      document.removeEventListener('mousedown', handleClickOutside);
    }

  })
  const handleClickOutside=(event)=>{
    if (wrapperRef && !wrapperRef.current.contains(event.target)) {
      setIsOpenModal(false);
    }
    else {
      setIsOpenModal(true);
    }
  }
 
    return (<div ref={wrapperRef} value={isOpenModal} className="modal">
      {children}

    </div>);
  
}
export default Modal;

리액트의 useRef를 통해 document의 요소를 잡아주고,

클릭이벤트를 받아 영역 여부를 판단해주는 handleClickOutside메소드를 선언해줍니다.

 

여기서 추가적으로 모달 창 내부의 내용의 display여부를 받아주는 isOpenModal을 부모 컴포넌트에서 선언해줍니다.

 

uesEffect (컴포넌트가 생성 시점)에서

이벤트 리스터 'mousedown'을 추가해주고 handleClickOutside메소드를 호출해줍니다.

 

uesEffect(컴포넌트가 소멸된 시점)에서 이벤트 리스터 'mousedown'을 remove 해줍니다.

 

그러면 마우스가 클릭될 때마다 handleClickOutside메소드가 호출되고 클릭한 부분이 wrapperRef에 포함되어 있지 않다면 isOpenModal을 false로 아니라면 true로 변경을 해줍니다.

 

그리고  jsx부분에서는 가장 바깥 div를 wrapperRef로 설정해주고 마지막으로 컴포넌트 내부는 children 속성값들로 지정해 주면 됩니다.

{isOpenModal && 
  <Modal isOpenModal={isOpenModal} setIsOpenModal={setIsOpenModal}>
  	<div>내부</div>
  </Modal>}

적용할 부모 컴포넌트에서 위와 같이 사용해주면 됩니다.

 

 

코드는 여기서 참고했습니다 💻

https://codesandbox.io/s/30q3mzjv91?module=%2Fsrc%2FOutsideAlerter.js

 

Outside Alerter - React ^16.2.0 - CodeSandbox

Outside Alerter - React ^16.2.0 by benox3 using react, react-dom, react-scripts

codesandbox.io


포스팅 마치겠습니다 🧡

반응형