React로 Modal 만들기

React를 사용하여 Modal을 작성했다는 이야기



결론



이번에는 도서관을 사용한다고 말하는 것에 침착했다.

거기에 이르기까지의 경위



1.hooks & Portal 사용



포털이란?



포털은 부모 구성 요소의 DOM 계층 구조 외부의 DOM 노드에 대한 하위 구성 요소를 렌더링하는 공식 메커니즘을 제공합니다. (인용: htps : // 그럼. Rea ctjs. rg / cs / rta ls. HTML )

구현 방법



index.html에 model용 DOM 설치

index.html
<!doctype html>
  <html lang="ja">
  <head>
    <title>modal test</title>
    <meta charset="UTF-8">
    <meta name="format-detection" content="telephone=no">
    <meta name="keywords" content="~~"><meta name="description" content="~~">
    <meta name="viewport" content="width=device-width">
    <link rel="icon" href="/favicon.png">
  </head>
  <body>
    <main role="main">
      <div id="app"></div>
      <div id="modal"></div>
    </main>
    <script src="/js/main.js"></script>
  </body>
</html>
id="modal" 아래에 렌더링 할 구성 요소 만들기

ModalPortal.jsx
import ReactDOM from 'react-dom';

export const ModalPortal = ({ children }) => {
  // index.html内にあるid=modalの要素を取得
  const el = document.getElementById('modal');
 // children = modal を el = modal要素 へ レンダー
  return ReactDOM.createPortal(children, el);
};


이것으로 모드를 표시할 준비가 완료된 후에는 모드의 내용의 컴퍼넌트를 준비
다음 구성 요소는 ModalPortalchildren 값입니다.

Modal.jsx
export const Modal = () => {
  return (
    <div>
      <h3>Modalコンポーネント</h3>
      <button>閉じる</button>
    </div>
  );
};

그리고

App.jsx
import ReactDOM from 'react-dom';
import Modal from "./Modal";
import ModalPortal from "./ModalPortal";
import 'react-hot-loader'


const app = document.getElementById('app')
const App = () => {
  return (
    <div>
      <h1>Modal実装したった</h1>
      <ModalPortal>
        <Modal />
      </ModalPortal>
    </div>
  )
}

ReactDOM.render(<App />,app)

그런 다음 useState, useRef에서 처리를 추가하여 Modal 같은 동작을 구현합니다.

useRef와 useState의 처리에 대해 가볍게 설명



useState에서 버튼을 눌렀을 때에, 모달을 표시할지의 state를 준비해, 표시 비표시를 실시하고 있습니다.
useRef에서는, modal의 외측을 클릭했을 때, 숨기기를 실시하기 위해서 클릭된 요소가 외측의 요소인지 판정시키기 위해서 준비하고 있습니다. (손 빼고 미안합니다.)

왜 그만두었는가



modal내에서 model외로의 onClick에서도 발화해 버린다.

방금 전에 useRef에서 바깥쪽을 클릭했을 경우 모달을 숨기게 한다는 것이었습니다만, 안쪽에서 바깥쪽으로의 클릭으로도 발화해 버린다.



생각할 수 있는 대책 방법



onClick 대신 mousedown과 touchstart로 요소를 구분합니다. mousedown과 touchstart 두 가지 필요한 이유는 PC와 SP에서 이벤트 발화가 다르기 때문에 두 가지 준비해야합니다.
하지만, 스크롤 때도 발화하지 않을까 등 불안 요소가 있었기 때문에, 시간이 걸리려고 느끼고 단념했습니다

2.react-modal 사용



구현 시간도 제한되어 있으므로 라이브러리에서 해 봅시다.





구현 내용



이미지대로 install에서 가서
// npm
$ npm install --save react-modal
// yarn
$ yarn add react-modal
import React, { useState } from 'react'
import { jsx } from '@emotion/react'
import Modal from 'react-modal'
export const useModal = () => {
  const [modal, setModal] = useState(false)
  const modalOpen = () => { setModal(true) return }
  const modalClose = () => { setModal(false) }
  return { modal, modalOpen, modalClose }
}
export const ModalBox = (props) => {
  Modal.setAppElement('#modal')
  const customStyles = {
    overlay: { position: 'fixed', top: 0, width: '100%', height: '100%'},
    content: { position: 'static', maxWidth: props.maxWidth}
  };
  const modalClose = () => { props.close() }
  return (
    <Modal isOpen={props.modal} onRequestClose={modalClose} style={customStyles}>
      {props.children}
    </Modal>
  );
};
  • useModal에서 Modal 제어
  • Modal.setAppElement에서 모달을 표시하는 DOM 설정
  • customStyles
  • overlay: Modal 외부 설정
  • content: Modal 내용 설정

  • 나중에 표시하기 만하면 문제가 해결됩니다

  • 여담



    Modal을 작성한 후 찾은 편리한 후크를 소개하고 싶습니다.
    방금 외부의 onClick 문제를 해결한 것입니다.

    좋은 웹페이지 즐겨찾기