개발 노트

modal dialog component만들기 본문

React

modal dialog component만들기

한츄 2024. 3. 20. 14:23

1. zustand 에 modal dialog관련 store생성하기

import {create} from 'zustand';

interface ModalState {
  isModalOpen: boolean;
  openModal: () => void;
  closeModal: () => void;
}

// 모달 상태를 관리하는 스토어
export const useModalStore = create<ModalState>((set) => ({
  isModalOpen: false, // 모달의 초기 상태는 닫혀있음
  openModal: () => set({ isModalOpen: true }), // 모달을 여는 액션
  closeModal: () => set({ isModalOpen: false }), // 모달을 닫는 액션
}));

 

 

2. Component만들기

  • draggable한 modalComponent를 만들기위해 mouseup mousedown mousemove이벤트핸들러 이용
  • 뒤쪽 배경을 누르면 종료되게 설정 이벤트 버블링을 막기위해서 e.stopPropagation과 e.preventDefault 적절하게 활용하기
  • 배경보다 상위에 노출되기 위해 z-index적용하기
import { useState, useEffect } from 'react';
import { useModalStore } from '@/store/useModalStore';

// 마우스 이벤트 핸들러에서 사용될 위치 타입 정의
interface Position {
  x: number;
  y: number;
}

const ModalComponent: React.FC = () => {
  const { isModalOpen, closeModal } = useModalStore();
  const [position, setPosition] = useState<Position>({ x: 0, y: 0 });
  const [dragging, setDragging] = useState<boolean>(false);
  
  // 마우스 클릭 위치 저장 변수의 타입도 Position으로 지정
  const [rel, setRel] = useState<Position | null>(null);
  const { groupedMessages } = useMqttWorkerStore();

//표시될 내용 관련부분 생략

  useEffect(() => {
    // 화면의 크기를 기반으로 중앙 위치 계산
    const updatePosition = () => {
      const x = window.innerWidth / 2;
      const y = window.innerHeight / 2;
      setPosition({ x, y });
    };

    // 컴포넌트 마운트 시에 위치 업데이트
    updatePosition();
  }, []); // 빈 의존성 배열로 마운트 시에만 실행
  useEffect(() => {
    const moveHandler = (e: MouseEvent) => handleMouseMove(e);
    const upHandler = (e: MouseEvent) => handleMouseUpDOM(e);

    if (dragging) {
      document.addEventListener('mousemove', moveHandler);
      document.addEventListener('mouseup', upHandler);
    } else {
      document.removeEventListener('mousemove', moveHandler);
      document.removeEventListener('mouseup', upHandler);
    }

    return () => {
      document.removeEventListener('mousemove', moveHandler);
      document.removeEventListener('mouseup', upHandler);
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [dragging, rel]);

  if (!isModalOpen) return null;

  const handleMouseDown = (e: React.MouseEvent<HTMLDivElement>) => {
    setDragging(true);
    setRel({
      x: e.pageX - position.x,
      y: e.pageY - position.y,
    });
    e.stopPropagation();
    e.preventDefault();
  };

  const handleMouseMove = (e: MouseEvent) => {
    if (!dragging || !rel) return;
    setPosition({
      x: e.pageX - rel.x,
      y: e.pageY - rel.y,
    });
    e.stopPropagation();
    e.preventDefault();
  };

  // DOM 이벤트를 위한 핸들러
  const handleMouseUpDOM = (e: MouseEvent) => {
    if (!dragging) return;
    setDragging(false);
    e.stopPropagation();
    e.preventDefault();
  };

  // 리액트 이벤트를 위한 핸들러
  const handleMouseUpReact = (e: React.MouseEvent<HTMLDivElement>) => {
    e.stopPropagation();
    e.preventDefault();
    setDragging(false);
  };

  return (
    <div onClick={closeModal} className="fixed bg-[rgba(167,221,158,0.5)] w-screen h-screen z-[100] top-0">
      <div
        style={{ left: `${position.x}px`, top: `${position.y}px` }}
        className="fixed bg-white border min-w-96 min-h-80 p-5 rounded-lg cursor-move"
        onMouseDown={handleMouseDown}
        onMouseUp={handleMouseUpReact}
        onClick={(e)=>e.stopPropagation()}
      >
         <p className="text-black">모달창입니다</p>
        <button
          type="button"
          onClick={(e: React.MouseEvent<HTMLButtonElement>) => {
            e.stopPropagation();
            closeModal();
          }}
          className="absolute text-lg top-4 right-5"
        >
          ×
        </button>
      </div>
    </div>
  );
};

export default ModalComponent;

 

3. Component호출하기

'React' 카테고리의 다른 글

새 글 정보 알람 기능  (0) 2024.03.22
로컬스토리지에 값 저장하기  (0) 2024.03.22
필터기능 구현  (0) 2024.03.18
자료구조 변경 비교  (0) 2024.03.13
Next.js에서 mysql2 연결하기 (net error 해결기)  (0) 2024.02.29