본문 바로가기
리액트 궁금증

react-modal을 사용한 모달 만들기

by 띠리에이터 2024. 6. 2.
react-modal npm 설치
$ npm install --save react-modal
$ yarn add react-modal

 

redact-modal의 옵션들 
interface Styles {
	content?: React.CSSProperties | undefined;
    overlay?: React.CSSProperties | undefined;
    }

// react-modal Styles 옵션에는 content와 overlay가 있다.
// content : 모달창 내부영역 디자인
// overlay : 모달 외부영역 디자인

interface Props {
	isOpen: boolean;
    // 모달의 열림을 결정
    
    shouldCloseOnOverlayClick?: boolean | undefined;
    // 모달창 바깥을 클릭하면 모달창이 닫히는지 여부, 기본값이 true로 설정
    
    shouldCloseOnEsc?: boolean | undefined;
    // esc를 누르면 모달창 닫히는지 여부 , 기본값이 true로 설정
    
    onRequestClose?(event: React.MouseEvent | React.KeyboardEvent): void;
    // 모달의 닫힘을 결정
    
    ariaHideApp?: boolean | undefined
    // app요소의 숨김을 결정
}

//이 옵션들 외에도 많은 옵션들 있다.

 

  • react-modal을 사용하면 아래와 같은 에러를 볼 수 있다. 

Screen Reader 가 react-modal이 열릴 때 사용자가 modal에 집중할 수 있도록 메인 컨텐츠를 읽지 못하도록 숨겨야 하는데 숨기는 대상이 지정되지 않았을 때 발생된다. 

이때 ariaHideApp={false}를 사용해서 모달이 열릴 때 최상위 요소를 숨겨주면 에러를 해결할 수 있다. 

react-modal 라이브러리를 활용한 모달창 구현 방법
  1. 공통 모달 만들기
    • React-modal을 import 해준 뒤 tsx파일의 return문 안에 모달창 내용을 작성
    • react-modal로 공통 모달을 만들고 많은 옵션 들 중에서 isopen, onReqyestClose, style, children 을 props로 넘겨줘서 상위 컴포넌트에서 스타일을 지정하고 데이터를 넣을 수 있게 만든다.
import React from "react";
import Modal from "react-modal";

type ModalProps = {
  children?: React.ReactNode;
  isopen: boolean;
  onRequestClose: () => void;
  style: ReactModal.Styles;
};

const CommnModal = ({
  children,
  isopen,
  onRequestClose,
  style,
}: ModalProps) => {
  return (
    <Modal isOpen={isopen} 
    style={style} 
    onRequestClose={onRequestClose}
    ariaHideApp={false}>
      {children}
    </Modal>
  );
};

export default CommnModal;

//children -> 모달 안에서 사용 될 데이터
//isopen -> 모달의 열림 결정
//onRequestClose -> 모달의 닫힘 결정
//style -> 모달의 overlay와 content 스타일

2. 공통 모달을 사용한 GallerydetailModal 만들기

  • GallerydetailModal에서 스타일 지정
  • children에 들어갈 내용 및 데이터 작성 
import React from "react";
import CommnModal from "shared/ui/commonModal";
import styles from './galleryDetail.module.css'

type GalleryDetailModalProps = {
  modalOpen: boolean;
  setModalOpen: (isOpen: boolean) => void;
};

const customModalStyles: ReactModal.Styles = {
  overlay: {
    backgroundColor: " rgba(0, 0, 0, 0.4)",
    width: "100%",
    height: "100vh",
    zIndex: "10",
    position: "fixed",
    top: "0",
    left: "0",
  },
  content: {
    width: "80%",
    height: "80%",
    zIndex: "11",
    position: "absolute",
    top: "50%",
    left: "50%",
    transform: "translate(-50%, -50%)",
    borderRadius: "10px",
    backgroundColor: "rgba(0, 0, 0, 0.4)",
  },
};

const GalleryDetailModal = ({
  modalOpen,
  setModalOpen,
}: GalleryDetailModalProps) => {
  return (
    <CommnModal
      isopen={modalOpen}
      onRequestClose={() => setModalOpen(false)}
      style={customModalStyles}
    >
      <div>테스트1234</div>
    </CommnModal>
  );
};

export default GalleryDetailModal;

 

3. 모달이 필요한 컴포넌트에서 GalleryDetailModal 컴포넌트 사용

 

import React from "react";
import styles from "./galleryCard.module.css";
import { GalleryCardType } from "shared/type/Gallery";
import { useState } from "react";
import GalleryDetailModal from "features/galleryDetailModal/ui";

const GalleryCard = ({ title, imgUrl }: GalleryCardType) => {
  const [modalOpen, setModalOpen] = useState(false);

  const modalClick = () => {
    setModalOpen(true);
  };

  return (
    <div className={styles.container}>
      <img
        src={imgUrl}
        alt="갤러리 이미지"
        className={styles.image}
        onClick={modalClick}
      />
      <div className={styles.title}>{title}</div>
      <GalleryDetailModal
        modalOpen={modalOpen}
        setModalOpen={() => setModalOpen(false)}
      />
    </div>
  );
};

export default GalleryCard;

'리액트 궁금증' 카테고리의 다른 글

[react-query] 2. react-query의 status  (0) 2024.06.17
[react-query] 1. react-query와 useQuery알아보기  (0) 2024.06.17
useReducer 다시 찾아볼것  (0) 2024.02.02
React children  (0) 2024.01.18
01 10 리액트 props 는 뭘까  (0) 2024.01.10