プログラム関係の備忘録。技術系記事1000記事以上を目指すブログ

【React】reactstrapを使って汎用的なモーダルコンポーネントを作る

  • 2020年6月1日
  • 2020年6月1日
  • JavaScript
  • 1627view
  • 0件

はじめに

React.jsを使ったフロントを作成していて、なにかの操作を実行する際。
いきなり行うのではなく一旦確認を挟みたいときなどに便利な、モーダルウィンドウの実装方法を紹介していきます。

パッケージのインストール

reactstrapというものを使います
https://reactstrap.github.io/

これはBootstrap4をreactのコンポーネント指向で簡単に扱うことができるreact版Bootstrapです。

reactstrapをを使えば上記リンク内のサンプルにあるように様々なパーツを使うことができるようになりますが、今回はモーダルの表示に絞って解説していきます。

インストール手順は割愛しますので、上記リンクにあるようにnpm経由などでインストールしておいてください。

基本的なモーダル

import React, { useState } from 'react';
import { Button, Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap';

const ModalExample = (props) => {
  const {
    buttonLabel,
    className
  } = props;

  const [modal, setModal] = useState(false);

  const toggle = () => setModal(!modal);

  return (
    <div>
      <Button color="danger" onClick={toggle}>{buttonLabel}</Button>
      <Modal isOpen={modal} toggle={toggle} className={className}>
        <ModalHeader toggle={toggle}>Modal title</ModalHeader>
        <ModalBody>
          Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
        </ModalBody>
        <ModalFooter>
          <Button color="primary" onClick={toggle}>Do Something</Button>{' '}
          <Button color="secondary" onClick={toggle}>Cancel</Button>
        </ModalFooter>
      </Modal>
    </div>
  );
}

export default ModalExample;

上記のようにコンポーネントを作成し、任意のコンポーネントに読み込ませることで、以下のようにモーダルが立ち上がります。

汎用的なモーダルに改良する

このサンプルのままだと、表示する内容ごとにモーダルのコンポーネントを作らないといけないし、Do Somethingボタンを押したときのイベントも設定しなくてはいけないので、以下のように改良してみました。

import React, { useState } from 'react';
import { Button, Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap';
import MessageInfo from './MessageInfo';

/**
 * モーダル
 */
const ModalArea = (props) => {
  const {
    buttonName,
    modalTitle,
    modalBody,
    modalAction,
    message,
    color,
    buttonColor
  } = props;

  const [modal, setModal] = useState(false);

  const toggle = () => setModal(!modal);

  const clicked = () => modalAction();

  return (
    <div>
      <Button
        outline block 
        color={buttonColor}
        className="mb-3 btn-sm"
        onClick={toggle}
        >{buttonName}
      </Button>
      <Modal isOpen={modal} toggle={toggle}>
        <ModalHeader toggle={toggle}>{modalTitle}</ModalHeader>
        <ModalBody>{modalBody}</ModalBody>
          <MessageInfo
            message={message}
            color={color}
          />
        <ModalFooter>
          <Button color="secondary" 
            className="mb-3 btn-sm"
            onClick={toggle}>閉じる
          </Button>
          { !message ? 
            <Button 
              className="mb-3 btn-sm"
              color="success" onClick={() => {clicked()}}>実行する
            </Button>
          : null}
        </ModalFooter>
      </Modal>
    </div>
  );
}

export default ModalArea;

解説

propsとして以下を追加しています

buttonName: モーダルを表示するボタンのラベル
buttonColor: モーダルを表示するボタンのカラー
modalTitle: モーダル内に表示するタイトル名
modalBody: モーダル内に表示するコンテンツ部分
modalAction: モーダル内「実行」ボタン押下時の関数部分
message: モーダル内の処理結果によって表示するAlart内容
color: モーダル内の処理結果によって表示するAlartのカラー

上記でさらに読み込んでいるMessageAreaというのは、message内容と色を渡せばその内容のAlartを返してくれる自作コンポーネントです。

呼び出し方法

任意のコンポーネント内で上記のModalAreaコンポーネントをインポートし、以下のようにpropsを指定します。

<ModalArea
  buttonName="投稿する"
  modalTitle="投稿確認"
  modalBody="入力した内容で投稿しますか?"
  message={this.state.message}
  color={this.state.color}
  buttonColor="success"
  modalAction={() => { this.doSubmit(); }}
/>

こうすることで、様々な場面で一つのコンポーネントを使いまわすことができます。
ポイントは、modalActionが呼び出されたときに親コンポーネントの関数を呼び出すようにしているので、実行処理自体はそれぞれ別定義できる点です。

親コンポーネントのdoSubmit()の結果によって、messageに内容を入れれば、モーダル内にアラートが表示されるといったようにしています。