PR

ReactとMUIでモーダルウインドウを簡単に作成する!

記事内に広告が含まれています。
SNSフォローボタン
z_a_k_iをフォローする

本記事では、ReactとMUIでモーダルウインドウを作成する方法をご紹介します。

こんな悩みをお持ちの方にオススメ!
  • Reactでモーダルウインドウを実装したい
  • モーダルウインドウを利用するイメージが知りたい
  • とりあえず自分のアプリにモーダルウインドウを組み込みたい

Reactでは、CSSフレームワークが多く公開されていて、おしゃれな画面を簡単に作れて便利ですよね。

中でも「MUI」は無料で利用できて人気のフレームワークのため、利用している開発者も多いのではないでしょうか。

MUIで画面をおしゃれにしたあとは、情報を入力する入力フォームもおしゃれにしたくありませんか。

今回はおしゃれな入力フォームを作成する方法としてモーダルウインドウの使い方を紹介します

ReactとMUIを利用している方には、ソースコードをそのまま流用し、モーダルウインドウを簡単に組み込めます

ぜひ最後までご覧ください。

作成する入力フォーム

作成する入力フォームはこちら。サブウインドウとして入力フォームが表示されます。

入力フォーム表示中は、メインの画面は暗くなる最近のトレンドの入力フォームです。

この記事では、体重と筋トレ回数を記録するアプリにモーダルウインドウを組み込んでいます。

このアプリに限らずどんなアプリにもモーダルウインドウを組み込めます。

そもそもモーダルウインドウってなに?
困ってる人
困ってる人

当たり前のように「モーダルウインドウ」って言ってるけど、そもそも「モーダルウインドウ」ってなに?

ウインドウの種類には、メインとなる画面の「メインウインドウ」と、メインウインドウ上で呼び出される小さめの画面の「サブウインドウ」が存在します。

「サブウインドウ」は「メインウインドウ」の補助画面として利用される画面です。

モーダルウインドウとは、「サブウインドウ」の一つです。サブウインドウが表示中はメインウインドウを操作できないように制御したものを「モーダルウインドウ」と呼びます。

  • 「モーダルウインドウ」とはサブウインドウの一つ。
  • サブウインドウ表示中、メインウインドウを操作できないようにしたもの「モーダルウインドウ」という。

モーダルウインドウの実装

ここから、モーダルウインドウを実装していきます。

ライブラリのインストール

モーダルウインドウ用のライブラリをインストールします。

Reactプロジェクトのフォルダに移動し、以下のコマンドを実行してください。

npm install --save react-modal

わたしはnpmを使っているので、npmでのインストール方法を紹介していますが、yarnでのインストールも可能です。

モーダルウインドウの実装

モーダルウインドウの実装手順を順番に解説していきます。最後には全体ソースを紹介します。

ライブラリのインポート

モーダルコンポーネントを利用するため、対象のプログラムでreact-modalをインポートします。

// モーダル関連
import Modal from "react-modal";

Modalコンポーネントの配置

「Modal」コンポーネントを配置します。メインとなるコンテンツの外側に配置してください。

          <Box display="flex" flexDirection='column' alignItems="center">
        ・・・メインウインドウのコンテンツ
          </Box>
          <Box m={2}>
            <Modal>
            ...モーダルウインドウのコンテンツ
            </Modal>
          </Box>

Modalウインドウの状態管理のためのstateを定義

モーダルウインドウのオープン・クローズ状態を管理するstateを定義します。以下のコードを記述してください。

const [editModalIsOpen, setEditModalIsOpen] = useState(false);

モーダルウインドウのクローズイベントの定義

モーダルウインドウを閉じるための関数を作成します。

stateの値と連動してウインドウの表示・非表示を切り替える仕組みのため、処理の内容はstateの値をFalseにするだけです。

  const closeModal = () => {
    setEditModalIsOpen(false);
  };

ModalウインドウのisOpenプロパティの設定

Modalコンポーネントの「isOpen」プロパティに作成したstateを設定します。この設定でstateの値と連動してモーダルウインドウが表示されます。

<Modal
  isOpen={editModalIsOpen}
  ・・・

ModalウインドウのonRequestCloseプロパティの設定

Modalコンポーネントの「onRequestClose」プロパティに上で作成した「closeModal」関数を設定します。

これにより、画面上のモーダルウインドウ以外の部分をクリックするとcloseModal関数が呼び出され、モーダルウインドウが非表示になります。

<Modal
  isOpen={editModalIsOpen}
  onRequestClose={closeModal}
  ・・・

Modalウインドウを表示するボタンの作成

メインコンテンツに、モーダルウインドウを起動するボタンを配置します。

以下のコードを実装することで、ボタンをクリックするとモーダルウインドウが開くようになります。

<Box sx={{ width: '90%'}}>
  <Button style={{width:'100%', height: '60px'}} variant="contained" startIcon={<AddIcon/>} color="secondary" onClick={() => {setEditModalIsOpen(true);}}></Button>
</Box>

ソースコード全体

ソースコードの全体はこちら。ここまで説明した内容が組み込まれています。モーダルウインドウ部分をコピーすることで、どのアプリケーションにもモーダルウインドウを組み込めます。

import './App.css';
import React, { useState,useEffect } from 'react';
import {
  Box, 
  Button, 
  TextField,
  Chip,
  Container,
  InputLabel,
} from '@mui/material';
import {
  Add as AddIcon, Edit as EditIcon, DeleteOutlined as DeleteIcon, Save as SaveIcon, Close as CancelIcon, 
  LineAxis as LineAxisIcon, MultilineChart as MultilineChartIcon, Dataset as DatasetIcon, Done as DoneIcon , Close as CloseIcon,
  ScaleTwoTone as ScaleTwoToneIcon, FitnessCenterTwoTone as FitnessCenterTwoToneIcon, CalendarMonth as CalendarMonthIcon
} from '@mui/icons-material';

// モーダル関連
import Modal from "react-modal";
import InputAdornment from '@mui/material/InputAdornment';


function App() {

  // 入力内容保持用state
  const [inputDate, setInputDate] = useState(new Date(date));
  const [inputWeight, setInputWeight] = useState(0);
  const [inputTrainingArm, setInputTrainingArm] = useState(0);
  const [inputTrainingShoulder, setInputTrainingShoulder] = useState(0);
  const [inputTrainingAbdomen, setInputTrainingAbdomen] = useState(0);
  const [inputTrainingBack, setInputTrainingBack] = useState(0);
  

  // モーダルウインドウ関連
  const [editModalIsOpen, setEditModalIsOpen] = useState(false);
  function updateLunchList() {
    ・・・割愛・・・
  }
  const closeModal = () => {
    setEditModalIsOpen(false);
  };

  return (    
          <Box display="flex" flexDirection='column' alignItems="center">
        ・・・メインウインドウのコンテンツ
              // モーダルウインドウを表示するボタン
              <Box sx={{ width: '90%'}}>
                <Button style={{width:'100%', height: '60px'}} variant="contained" startIcon={<AddIcon/>} color="secondary" onClick={() => {setEditModalIsOpen(true);}}></Button>
              </Box>
          </Box>
          <Box m={2}>
            <Modal
              isOpen={editModalIsOpen}
              onRequestClose={closeModal}
              style={{
                overlay: {
                  display: 'flex',
                  alignItems: 'center',
                  justifyContent: 'center',
                  backgroundColor: 'rgba(0, 0, 0, 0.5)', // 背景の透明度を調整
                },
                content: {
                  position: 'relative',
                  top: 'auto',
                  left: 'auto',
                  right: 'auto',
                  bottom: 'auto',
                  maxWidth: '90%', // モーダルの最大幅を調整
                  maxHeight: '90%', // モーダルの最大高さを調整
                  transform: 'none', // 位置調整のためのtransformをリセット
                  width: '90%'
                },
              }}
            >
              <Box mb={2}>
                <Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
                  <Box display="flex" justifyContent="center">
                    <TextField id="date-field" label="date" variant="standard" type="date"
                      value={inputDate} onChange={(e) => setInputDate(e.target.value)} sx={{ width: '80%'}}
                      InputProps={{
                        startAdornment: (
                          <InputAdornment position="start">
                            <CalendarMonthIcon />
                          </InputAdornment>
                        ),
                      }} />
                  </Box>
                  <Box display="flex" justifyContent="center">
                    <TextField id="weight-field" label='weight' variant="standard" type="number"
                      value={inputWeight} onChange={(e) => setInputWeight(e.target.value)} sx={{ width: '80%'}}
                      InputProps={{
                        startAdornment: (
                          <InputAdornment position="start">
                            <ScaleTwoToneIcon />
                          </InputAdornment>
                        ),
                      }} />
                  </Box>
                  <Box display="flex" justifyContent="center">
                    <TextField id="arm-field" label="arm" variant="standard" type="number"
                      value={inputTrainingArm} onChange={(e) => setInputTrainingArm(e.target.value)} sx={{ width: '80%'}} 
                      InputProps={{
                        startAdornment: (
                          <InputAdornment position="start">
                            <FitnessCenterTwoToneIcon />
                          </InputAdornment>
                        ),
                      }} />
                  </Box>
                  <Box display="flex" justifyContent="center">
                    <TextField id="shoulder-field" label="shoulder" variant="standard" type="number"
                      value={inputTrainingShoulder} onChange={(e) => setInputTrainingShoulder(e.target.value)} sx={{ width: '80%'}}
                      InputProps={{
                        startAdornment: (
                          <InputAdornment position="start">
                            <FitnessCenterTwoToneIcon />
                          </InputAdornment>
                        ),
                      }} />
                  </Box>
                  <Box display="flex" justifyContent="center">
                    <TextField id="abdomen-field" label="abdomen" variant="standard" type="number"
                      value={inputTrainingAbdomen} onChange={(e) => setInputTrainingAbdomen(e.target.value)} sx={{ width: '80%'}} 
                      InputProps={{
                        startAdornment: (
                          <InputAdornment position="start">
                            <FitnessCenterTwoToneIcon />
                          </InputAdornment>
                        ),
                      }} />
                    </Box>                  
                  <Box display="flex" justifyContent="center">
                    <TextField id="back-field" label="back" variant="standard" type="number"
                      value={inputTrainingBack} onChange={(e) => setInputTrainingBack(e.target.value)} sx={{ width: '80%'}} 
                      InputProps={{
                        startAdornment: (
                          <InputAdornment position="start">
                            <FitnessCenterTwoToneIcon />
                          </InputAdornment>
                        ),
                      }} />
                  </Box>
                  <Box sx={{ display: 'flex', flexDirection: 'row', gap: 2 }} justifyContent="center" >
                    <Button variant="outlined" color="error" startIcon={<CloseIcon />} onClick={closeModal} sx={{ width: '40%', height: '60px'}}></Button>
                    <Button variant="outlined" color="success"  startIcon={<DoneIcon />} onClick={updateForFormData} sx={{ width: '40%', height: '60px'}}></Button>
                  </Box>
                </Box>
              </Box>
            </Modal>
          </Box>
  );
}

export default App;

まとめ

この記事のまとめです。

  • モーダルウインドウは「react-modal」で簡単に組み込める
  • 作成したモーダルウインドウは他のアプリケーションにも流用できる

本記事では、ReactとMUIを使ってモーダルウインドウを作成する方法をご紹介しました。

ReactとMUIを利用することで、簡単にモーダルウインドウを作成することができます。

モーダルウインドウは最近トレンドのアプリケーションでよく使われます。

簡単に作成できる方法を知っていると開発速度が速くなりますので、ぜひ開発方法を習得してください。

本記事が参考になりましたら幸いです。

関連記事はこちら:【AWS】CloudFrontとS3を連携させてWebアプリを公開する

コメント