ReactでModal作成
Reactを使用してModal作成したっていう話
結論
今回はライブラリを使用するぜっていうことに落ち着いた。
そこに至るまでの経緯
1.hooks & Portalを使用
Portalとは
ポータル (portal) は、親コンポーネントの DOM 階層外にある DOM ノードに対して子コンポーネントをレンダーするための公式の仕組みを提供します。(引用:https://ja.reactjs.org/docs/portals.html)
実装方法
index.htmlにmodal用DOMを設置
<!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"
以下にレンダリングさせるコンポーネントを作成
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);
};
これでmodalを表示する準備は完了あとはmodalの内容のコンポーネントを用意
以下のコンポーネントがModalPortal
でのchildren
に値します
export const Modal = () => {
return (
<div>
<h3>Modalコンポーネント</h3>
<button>閉じる</button>
</div>
);
};
そして
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内からmodal外への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を作成し終えた後に見つけた便利なhookを紹介したいと思います。
先ほどの外側のonClick問題を解消したものになります。
Author And Source
この問題について(ReactでModal作成), 我々は、より多くの情報をここで見つけました https://qiita.com/nakamo-03/items/3f57b861742871ceacc8著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .