일기장 프로젝트에서 구현한 간단한 모달 메뉴 사용을 정리하고자 한다.
# 모달 메뉴가 있는 컴포넌트 (부모) : Diary.js
# 모달 메뉴 버튼 컴포넌트 (하위자식) : ToggleMenu.js
# 모달 메뉴 버튼을 클릭했을 때 나오는 메뉴 컴포넌트 (최하위 자식) : EditAndRemove.js
순으로 컴포넌트가 이루어져 있다.
부모 컴포넌트
-> id props를 넘겨주면서 자식 컴포넌트를 호출한다.
import ToggleMenu from "../components/ToggleMenu";
const Diary = () => {
...
return (
<div className="Diary">
...
<ToggleMenu id={id} />
...
)
};
export default Diary;
자식 컴포넌트
- open의 값이 true이면 메뉴가 열리고, false이면 닫히도록 state 이용
const [open, setOpen] = useState(false);
- menu button에 onClick() 함수로 toggleOpen() 함수를 넘겨준다.
- 현재 값이 true이면 false로 바꾸고, false이면 true로 바꾸도록 setState 해준다.
const toggleOpen = () => {
setOpen(!open);
};
- 메뉴 버튼에 ref 지정
const menuRef = useRef();
<button className={"menu_btn"} onClick={toggleOpen} ref={menuRef}>
- 현재 마우스의 클릭이 메뉴 영역으로 벗어나면 ( 외부 영역 클릭하면 ) 메뉴 닫히도록 구현
useEffect(() => {
const onClickOutside = (e) => {
if (open && !menuRef.current.contains(e.target)) {
setOpen(false);
}
};
document.addEventListener("click", onClickOutside);
return () => {
document.removeEventListener("click", onClickOutside);
};
}, [open]);
- 메뉴 이미지의 className을 open에 값에 따라 다르게 설정하여, 클릭 시 투명도를 조절함
<img
className={open ? "menu_img_clicked" : "menu_img"}
src={process.env.PUBLIC_URL + `/assets/menu.png`}
alt="menu"
/>
.ToggleMenu .menu_img_clicked {
opacity: 0.5;
}
최하위 자식 컴포넌트
- 메뉴에 띄우고자 하는 내용을 구현하면 된다.
자식 컴포넌트 (모달 호출 컴포넌트) 전체 코드
import { useState, useRef, useEffect } from "react";
import EditAndRemoveMenu from "./EditAndRemoveMenu";
const ToggleMenu = ({ id }) => {
const [open, setOpen] = useState(false);
const menuRef = useRef();
const toggleOpen = () => {
setOpen(!open);
};
useEffect(() => {
const onClickOutside = (e) => {
if (open && !menuRef.current.contains(e.target)) {
setOpen(false);
}
};
document.addEventListener("click", onClickOutside);
return () => {
document.removeEventListener("click", onClickOutside);
};
}, [open]);
return (
<div className="ToggleMenu">
<button className={"menu_btn"} onClick={toggleOpen} ref={menuRef}>
<img
className={open ? "menu_img_clicked" : "menu_img"}
src={process.env.PUBLIC_URL + `/assets/menu.png`}
alt="menu"
/>
</button>
{open && <EditAndRemoveMenu id={id} />}
</div>
);
};
export default ToggleMenu;