react-modalのシンプルな使い方
投稿日: 2024年10月04日
モーダルは画面遷移なしで入力フォーム開けたり、色んな情報見れるような画面作れたりするので便利だと思います。
ページが変わるよりストレスがないなと個人的には感じます。
私は個人開発の第一弾でモーダルをたくさん使用し、実務案件課題でも使用し、LPでも使用し、、結構実装しました。
さすがにマスターしたと言っても過言ではないと思います・・! (過言かも)
これからオリジナルアプリ開発する方の中にはモーダルが必要になる場面がある方も多いのではないかなと想像しております。
react-modalというライブラリを使うと簡単に実装できるので、その方法についてご紹介したいと思います!!
インストールしないと使えないので、まずはインストールします。
npm i react-modal
環境によっては型情報のインストールが必要なことがあります。
React-modalをimportした時に型云々エラーが出たらインストールでいいかと思いますw
npm i @types/react-modal
使いたいファイルでインポートします
import ReactModal from "react-modal";
いくつか紹介します。
開閉状況を管理するステート
モーダルが閉じられるリクエストが発生したときに呼び出されるコールバック関数。
例えば、背景クリックで閉じないようにしたい時は何も処理しない()=>{}
を渡したりします。
モーダル本体のクラス(文字列)
オーバーレイのクラス
モーダルを開いた際にアプリの他の部分を非表示にするかどうかの制御。
falseを渡すと非表示にする処理を無効化する
モーダルが開閉されるときのアニメーション遅延時間の設定
別途global.cssで実際のアニメーションを定義する必要あり
モーダルの内容を説明するためのアクセシビリティ用ラベル
Modalでラップした要素がモーダルに表示される要素になる
"use client";
import { faXmark } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import React, { FC,ReactNode } from "react";
import ReactModal from "react-modal";
interface Props {
isOpen: boolean;
onClose: (e: React.MouseEvent<HTMLElement>) => void;
children: ReactNode;
}
export const Modal: FC<Props> = ({ isOpen, onClose, children }) => {
return (
<ReactModal
isOpen={isOpen}
onRequestClose={onClose}
contentLabel="Modal"
closeTimeoutMS={300}
ariaHideApp={false}
className={`relative z-[99] h-screen w-screen bg-black/80`}
overlayClassName="fixed inset-0 bg-black_main bg-opacity-60 flex items-center justify-center z-[99]"
>
<div
className="flex size-full items-center justify-center"
onClick={onClose}
>
<button
className={`absolute right-0 top-0 z-[999] p-3`}
onClick={onClose}
>
<FontAwesomeIcon
className="text-[34px] text-[#ACAAA9]"
icon={faXmark}
/>
</button>
{children}
</div>
</ReactModal>
);
};
このコンポーネントにpropsを渡せばモーダルの出来上がりです。
Sleepでアプリガイドとして使用したコードを例に挙げてみます。
実際に上記のコンポーネントは使ってないのでそのままコピペで組み合わせるとデザインイマイチと思いますw
"use client";
import { faXmark } from "@fortawesome/free-solid-svg-icons";
import { faCheck } from "@fortawesome/free-solid-svg-icons";
import { faCircleInfo } from "@fortawesome/free-solid-svg-icons/faCircleInfo";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import Link from "next/link";
import { useState } from "react";
import { Modal } from "@/app/_components/modal";
export const GuideWithModal: React.FC = () => {
const [isOpen, setIsOpen] = useState(false);
const closeModal = () => {
setIsOpen(false);
};
const openModal = () => {
setIsOpen(true);
};
return (
<>
<div onClick={openModal} className="text-sm cursor-pointer">
<FontAwesomeIcon icon={faCircleInfo} className="pr-1" />
アプリガイド
</div>
<Modal isOpen={isOpen} onClose={closeModal} className="">
<h1 className="text-center pb-5">アプリガイド</h1>
<h2 className="text-sm pb-2 flex gap-1 items-center">
<FontAwesomeIcon icon={faCheck} className="h-5" />
睡眠データ登録の順番
</h2>
<p className="pb-5">
寝ていないと起きられない仕様になっています。一番最初は「寝かしつけ開始」または「寝た」のデータを登録してください。
<br />
※「寝かしつけ開始」の登録は任意です。
<br />
※「寝た」登録がないと「起きた」登録はできませんのでご注意ください。
</p>
<h2 className="text-sm pb-2 flex gap-1 items-center">
<FontAwesomeIcon icon={faCheck} className="h-5" />
直近の登録が「寝た」の場合の制御
</h2>
<p className="pb-5">
直近の登録が「寝た」の場合、「起きた」以外の登録は一括登録しか使うことができません。
<br />
また、「寝た」時刻より後の時間で一括登録を行うこともできません。
<br />
不整合なデータができることを阻止するためにそのような仕様にしております。
</p>
<div>
ご不便をおかけして申し訳ありません。
<br />
その他、疑問点等ありましたら、
<Link
href={
"https://www.instagram.com/sleep_app_info?igsh=enp1ZnprOThtbXFp&utm_source=qr"
}
target="_blank"
className="border-b-2 px-1 text-blue-500"
>
instagram
</Link>
からお気軽にDMいただきますようよろしくお願いいたします。
</div>
</Modal>
</>
);
};
簡単にですが要所のみ解説させていただきます。
const [isOpen, setIsOpen] = useState(false);
こちらがモーダルの開閉状況を管理するステートの定義です。
最初は閉じていてほしいので初期値はfalseです。
const closeModal = () => {
setIsOpen(false);
};
const openModal = () => {
setIsOpen(true);
};
どちらでも良さそうですが、開閉状況のステートの値を切り替える処理を関数にしています。
関数にしない場合は、例えばcloseModal
を渡している箇所に()=>{setIsOpen(false)}
を渡せば良いです。
closeModal関数はModalコンポーネントに渡すのと、children内のモーダル閉じるアイコンでも同じ処理をするので関数にした方が良いのかなという認識です。
<Modal isOpen={isOpen} onClose={closeModal} className="">
<div className="flex justify-end cursor-pointer" onClick={closeModal}>
・・・中略・・・
</div>
</Modal>
上記のようにpropsをそれぞれ渡して、モダール内に表示したい要素をModalタグでラップしたらOKです。
それだけです。
ライブラリ使えばモーダルは簡単に実装できます!!
実務案件課題等で使ったModalのコンポーネントはもっと良い感じに作られていましたが、個人開発ではこんな感じでもまぁ問題なく使えました。(多分w)
最低限感のある内容で恐縮ですが、どなたかのお役に立てたら幸いです・・!!
直近の案件で作ったModalコンポーネントに差し替えました!!
使い方の方とデザイン噛み合ってないかもですが、使用しているPropsも増やしたので参考になれば嬉しいです!