react hook에서 컴포넌트와 관련로직을 한번에 제공하기

Tony·2023년 3월 9일
0

react

목록 보기
70/86
post-custom-banner

컴포넌트와 컴포넌트에 사용할 관련 로직을 반복해서 사용해야 되는 경우 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;
profile
움직이는 만큼 행복해진다
post-custom-banner

0개의 댓글