컴포넌트와 컴포넌트에 사용할 관련 로직을 반복해서 사용해야 되는 경우 hook으로 묶어서 제공할 수 있다
// useContextMenu.tsx
import React, { useEffect, useState } from 'react';
interface MenuProps {
visible: boolean;
x: number;
y: number;
}
const Menu = ({ visible, x, y }: MenuProps) => {
return (
<div
style={{
position: 'absolute',
top: y,
left: x,
display: visible ? 'block' : 'none',
}}
>
<ul>
<li>메뉴1</li>
<li>메뉴2</li>
<li>메뉴3</li>
</ul>
</div>
);
};
const useContextMenu = () => {
const [state, setState] = useState({ visible: false, x: 0, y: 0 });
const handleContextMenu = (event: MouseEvent) => {
event.preventDefault();
setState({ visible: true, x: event.clientX, y: event.clientY });
};
const handleClick = () => {
setState({ visible: false, x: 0, y: 0 });
};
useEffect(() => {
document.addEventListener('contextmenu', handleContextMenu);
return () => {
document.removeEventListener('contextmenu', handleContextMenu);
};
}, []);
useEffect(() => {
document.addEventListener('click', handleClick);
return () => {
document.removeEventListener('click', handleClick);
};
}, []);
return { state, handleContextMenu, Menu };
};
export default useContextMenu;
사용 예
import React from 'react';
import useContextMenu from '@/hooks/useContextMenu';
const ContextMenu = () => {
const { Menu, state } = useContextMenu();
return (
<div>
<div>우클릭해보세요</div>
<Menu visible={state.visible} x={state.x} y={state.y} />
</div>
);
};
export default ContextMenu;
useContextMenu.tsx 에서 Menu를 포함한 이유는 Menu와 관련된 로직을 한번에 제공하기 위함이다
만약 컴포넌트가 hook안에 포함되는 것을 원하지 않는 다면 따로 분리 후 컴포넌트를 import 하고 hook에서 return으로 한번에 제공할 수도 있다
// Menu.tsx
import React from 'react';
interface MenuProps {
visible: boolean;
x: number;
y: number;
}
const Menu = ({ visible, x, y }: MenuProps) => {
return (
<div
style={{
position: 'absolute',
top: y,
left: x,
display: visible ? 'block' : 'none',
}}
>
<ul>
<li>메뉴1</li>
<li>메뉴2</li>
<li>메뉴3</li>
</ul>
</div>
);
};
export default Menu;
// useContextMenu.ts
import { useEffect, useState } from 'react';
import Menu from "./Menu.tsx";
const useContextMenu = () => {
const [state, setState] = useState({ visible: false, x: 0, y: 0 });
const handleContextMenu = (event: MouseEvent) => {
event.preventDefault();
setState({ visible: true, x: event.clientX, y: event.clientY });
};
const handleClick = () => {
setState({ visible: false, x: 0, y: 0 });
};
useEffect(() => {
document.addEventListener('contextmenu', handleContextMenu);
return () => {
document.removeEventListener('contextmenu', handleContextMenu);
};
}, []);
useEffect(() => {
document.addEventListener('click', handleClick);
return () => {
document.removeEventListener('click', handleClick);
};
}, []);
return { state, handleContextMenu, Menu };
};
export default useContextMenu;