티스토리 뷰
리액트에서 토글 메뉴를 구현하고, 메뉴 외부 영역을 클릭했을 때 메뉴가 닫히도록 구현하고자 했다.
import React, { useState, useRef, useEffect } from "react"
export const SubMenu = () => {
return (
<div className="sub-menu">
<ul className="sub-menu-list">
<li className="sub-menu-item">
<button type="button" className="btn-sub-menu">메뉴 1</button>
</li>
<li className="sub-menu-item">
<button type="button" className="btn-sub-menu">메뉴 2</button>
</li>
</ul>
</div>
)
}
export const Box = () => {
const subMenuRef = useRef<HTMLDivElement | null>(null)
const [subMenuShow, setSubMenuShow] = useState(false);
useEffect(() => {
const handleClose = (e: {target: any}) => {
if(subMenuShow && (!subMenuRef.current?.contains(e.target))) {
setSubMenuShow(false)
};
}
document.addEventListener('click', handleClose);
return () => document.removeEventListener('click', handleClose);
}, [subMenuShow])
return (
<li className="box-item">
<div className="box-area">
<div className="sub-menu-wrap" ref={subMenuRef}>
<button type="button" className="btn btn-post-manage" onClick={() => {setSubMenuShow(!subMenuShow)}}>버튼</button>
{subMenuShow && <SubMenu />}
</div>
</div>
</li>
)
}
먼저 <SubMenu>라는 토글 메뉴 컴포넌트를 만들어주었다.
그리고 useState를 통해 상태를 만들었고, subMenuShow가 true일 때 <SubMenu>가 나타나도록 했다.
useRef를 사용하여 외부영역이 아닌 버튼과 메뉴를 하나의 div에 묶어주었다.
그리고 useRef의 current에 담긴 엘리먼트가 아닌 요소가 클릭되었을 때 메뉴가 닫히도록 했다.
이벤트리스너를 제거해주지 않으면 컴포넌트가 리렌더링 될 때 마다 계속해서 이벤트리스너가 실행되므로,
컴포넌트가 언마운트될 때 removeEventListener로 이벤트를 제거해서 메모리 누수가 발생하지 않도록 했다.
참고 링크
https://yzlosmik.tistory.com/104
728x90
'개발 > react' 카테고리의 다른 글
[styled-components] keyframes 공통으로 사용하기 (0) | 2024.08.29 |
---|---|
[styled-components] 리액트 styled-components 사용하기 (3) | 2024.08.28 |
[React] 토글 클릭이벤트 구현 (0) | 2023.07.03 |
[React] 반복문으로 시간이 30분 간격으로 표시된 테이블 구현 (0) | 2023.07.02 |
[react] Cannot find module 'react-router-dom' 오류 해결 (0) | 2023.06.01 |
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크