ツクログ

tsukulognet

tsukulognet

道産子。Reactでなまら面白いものを作りたい。

【React】モーダルウィンドウを作る

eye catch

Reactで上記の画像のようなモーダルウィンドウを作ります。

開発環境の構築

ReactでUIを作るには、Reactの開発環境を構築する必要があります。

Reactの開発環境構築についてはReactの開発環境を構築するをご覧ください。

styled-componentsのインストール

コンポーネントにスタイルを持たせるために、ターミナルで以下のコマンドを実行してstyled-componentsをインストールします。

yarn add styled-components

コンポーネントを作る

src配下にcomponentsディレクトリを作成し、そこに以下のコンポーネントを作成します。

Button

ボタンのビューを返すButtonコンポーネントを作成します。

Buttonコンポーネントについては【React】ボタンを作るをご覧ください。

ModalWindow

モーダルウィンドウのビューを返すModalWindowコンポーネントを作成します。

components/ModalWindow.jsを以下の内容にします。

components/ModalWindow.js

import React from 'react'
import styled from 'styled-components'

const StyledModalWindow = styled.div`
    ${({ isClose, isShow }) =>
        isClose
            ? `visibility: hidden;`
            : isShow
            ? `visibility: visible;`
            : `visibility: hidden;`}
    z-index: 1000;
`;

const Overlay = styled.div`
    background-color: rgba(0, 0, 0, 0.6);
    position: fixed;
    top: -100vh;
    left: -100vw;
    bottom: -100vh;
    right: -100vw;
    z-index: 1;
`;

const ContentWrapper = styled.div`
    background-color: white;
    box-sizing: border-box;
    border-radius: 8vmin;
    color: #333;
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 60vmin;
    text-align: center;
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    min-width: 80vmin;
    z-index: 2;
    > button {
        position: absolute;
        top: 4vmin;
        right: 4vmin;
    }
`;

const Content = styled.div`
    max-height: 80vmin;
    padding: 4vmin;
`;

const Title = styled.h1`
    font-size: 4vmin;
    margin: 3vmin auto 0;
`;

const Text = styled.p`
    color: #777;
    font-size: 2vmin;
    margin: 4vmin 0 0;
`;

const ModalWindow = ({
    className,
    title,
    text,
    isShow,
    isShowCloseButton,
    children
}) => {
    const [isClose, setIsClose] = useState(false);
    return (
        <StyledModalWindow className={className} isShow={isShow} isClose={isClose}>
            <Overlay />
            <ContentWrapper>
                {isShowCloseButton && (
                    <Button bgColor="transparent" onClick={() => setIsClose(true)}>
                        ✖
                    </Button>
                )}
                <Content>
                    <Title>{title}</Title>
                    <Text>{text}</Text>
                    {children}
                </Content>
            </ContentWrapper>
        </StyledModalWindow>
    );
};

export default ModalWindow

ModalWindowコンポーネントが返すビューは次のコンポーネントで構成されています。

コンポーネント名 説明
StyledModalWindow ModalWindowコンポーネントが返すビューのスタイルを持つコンポーネント
Overlay オーバーレイを表示するコンポーネント
ContentWrapper モーダルウィンドウの内容を囲うラッパーコンポーネント
Button モーダルウィンドウを閉じるボタン
Content モーダルウィンドウの内容を表示するコンポーネント
Title モーダルウィンドウのタイトルを表示するコンポーネント
Message モーダルウィンドウのメッセージを表示するコンポーネント

また、ModalWindowコンポーネントはpropsとして以下の値を受け取ります。

props 説明
className クラス名
title モーダルウィンドウのタイトル
message モーダルウィンドウのメッセージ
isShow モーダルウィンドウを表示するかどうかを示す真偽値
isShowCloseButton 閉じるボタンを表示するかどうかを示す真偽値。表示する場合はtrueを指定する。
children モーダルウィンドウのコンテンツに含める内容

受け取ったpropsのうち、classNameは、ModalWindowコンポーネントが描画する親要素のクラス名になります。

titleとmessageはそれぞれモーダルウィンドウのタイトルとメッセージとしてそのまま出力され、childrenはContentコンポーネントが描画するDOMノードの子要素になります。

isShowはtrueであればStyledModalWindowコンポーネントのvisibilityプロパティがvisibleになり、モーダルウィンドウが表示されます。逆にfalseであればvisibilityプロパティはhiddenとなり、モーダルウィンドウが非表示になります。

isShowCloseButtonは閉じるボタンの条件付きレンダーの条件として使われており、trueであれば閉じるボタンをレンダーします。

また、ModalWindowコンポーネントはstateとしてisCloseという名前の値を持ちます。isCloseの初期値はfalseであり、モーダルウィンドウの閉じるボタンが押されたときにtrueに切り替わります。その結果、StyledModalWindowコンポーネントのvisibilityプロパティがhiddenとなり、モーダルウィンドウが非表示になります。

モーダルウィンドウを表示してみる

先ほど作成したコンポーネントを描画し、画面上にモーダルウィンドウを表示してみます。

App.jsを以下のように書き換えます。

App.js

import React from 'react'
import styled from 'styled-components'
import Button from './components/Button';
import Margin from './components/Margin';
import ModalWindow from './components/ModalWindow';

const App = () => {
    const [isShow, setIsShow] = useState(true);
    const handleClick = useCallback(() => setIsShow(false), []);

    const buttonTheme = {
        background: "orange",
        color: "#ffffff"
    };

    const buttonSize = {
        fontSize: "1vmin",
        padding: "2vmin 4vmin"
    };

    return (
        <div>
            <ModalWindow
                title="年齢認証"
                text="あなたは18歳以上ですか?"
                isShow={isShow}
                onClick={handleClick}
                isShowCloseButton={false}
            >
                <Margin top="2vmin" right="1vmin">
                    <Button onClick={handleClick} size={buttonSize}>
                        いいえ
                    </Button>
                </Margin>
                <Margin top="4vmin" left="1vmin">
                    <Button onClick={handleClick} theme={buttonTheme} size={buttonSize}>
                        はい
                    </Button>
                </Margin>
            </ModalWindow>
        </div>
    );
};

export default App

※Marginコンポーネントについては【React】marginをコンポーネントにするをご覧ください。

App.jsを上書き保存すると、ページ上にモーダルウィンドウが表示されます。

Demo