react-modalのシンプルな使い方

react-modalのシンプルな使い方

投稿日: 2024年10月04日

Tips
学習振り返り
要約
  • モーダルは画面遷移なしで情報を表示でき、便利なコンポーネントです。
  • react-modalライブラリを使うとモーダルの実装が簡単で、開閉状況を管理するステートを利用します。
  • 実務や個人開発での経験を基に、CustomModalコンポーネントを作成したコードとその使い方を紹介しました。

はじめに

モーダルは画面遷移なしで入力フォーム開けたり、色んな情報見れるような画面作れたりするので便利だと思います。

ページが変わるよりストレスがないなと個人的には感じます。

私は個人開発の第一弾でモーダルをたくさん使用し、実務案件課題でも使用し、LPでも使用し、、結構実装しました。

さすがにマスターしたと言っても過言ではないと思います・・! (過言かも)

これからオリジナルアプリ開発する方の中にはモーダルが必要になる場面がある方も多いのではないかなと想像しております。

react-modalというライブラリを使うと簡単に実装できるので、その方法についてご紹介したいと思います!!

インストール

インストールしないと使えないので、まずはインストールします。

npm i react-modal

環境によっては型情報のインストールが必要なことがあります。

React-modalをimportした時に型云々エラーが出たらインストールでいいかと思いますw

npm i @types/react-modal

インポート

使いたいファイルでインポートします

import ReactModal from "react-modal";

Props

いくつか紹介します。

isOpen

開閉状況を管理するステート

onRequestClose

モーダルが閉じられるリクエストが発生したときに呼び出されるコールバック関数。

例えば、背景クリックで閉じないようにしたい時は何も処理しない()=>{}を渡したりします。

className

モーダル本体のクラス(文字列)

overlayClassName

オーバーレイのクラス

ariaHideApp

モーダルを開いた際にアプリの他の部分を非表示にするかどうかの制御。

falseを渡すと非表示にする処理を無効化する

closeTimeoutMS

モーダルが開閉されるときのアニメーション遅延時間の設定

別途global.cssで実際のアニメーションを定義する必要あり

contentLabel

モーダルの内容を説明するためのアクセシビリティ用ラベル

children

Modalでラップした要素がモーダルに表示される要素になる

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も増やしたので参考になれば嬉しいです!

シェア!

Threads
user
吉本茜
山口在住/二児の母/育休中
記事一覧に戻る
Threads
0