LoginSignup
13
6

More than 3 years have passed since last update.

React Hooksを使ったモーダル実装

Last updated at Posted at 2020-06-25

React HooksのuseState・useRefを使ったモーダル実装についてまとめました。

今回実装するのは、以下のようなモーダルになります。

ezgif.com-video-to-gif (2).gif

完成コード

React


import React, {useState, useRef} from 'react';

const App = () => {
  const [modal, setModal] = useState(false)
  const modalRef = useRef()

  return (
    <div>
      <button onClick={() => setModal(true)}>Open</button>
      <div className={`modal__overlay ${modal && "is-opened"}`}  onClick={e=>{if(modalRef.current === e.target) setModal(false)}} ref={modalRef}>
        <div className="modal__box">
          <button className="modal__closeBtn" onClick={() => setModal(false)}>×</button>
          <div>モーダルテキスト</div>
        </div>
      </div>
    </div>
  );
}

export default App;

CSS

.modal__overlay{
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  background: rgba(0,0,0,0.4);
  z-index: 999;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  visibility: hidden;
  transition: opacity .3s, visibility .3s;
}
.is-opened{
  visibility: visible;
  opacity: 1;
}
.modal__box{
  background-color: #fff;
  position: relative;
  padding: 30px 20px;
}
.modal__closeBtn{
  position: absolute;
  top: 0;
  right: 0;
}

実装流れ

1.モーダルの見た目作成

まず、オーバーレイ要素(画面全体を覆う薄暗い要素)とモーダルボックスを作成します。


import React from 'react';

const App = () => {
  return (
    <div>
      {/* オーバーレイ要素でモーダルボックスを囲む */}
      <div className="modal__overlay">
        <div className="modal__box">
          <div>モーダルテキスト</div>
        </div>
      </div>
    </div>
  );
}

export default App;

.modal__overlay{
  /* 画面全体を覆う設定 */
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  background: rgba(0,0,0,0.4);
  z-index: 999;
  /* 画面中央にモーダルを表示させる設定 */
  display: flex;
  align-items: center;
  justify-content: center;
}
.modal__box{
  background-color: #fff;
  padding: 30px 20px;
}

ここまでの実装画面
スクリーンショット 2020-06-25 11.01.21.png

2.モーダルの表示切り替えの実装

次に、ボタンクリックでモーダルの表示・非表示を切り替えます。

// useState追加
import React, {useState} from 'react'; 

const App = () => {
  // モーダルの表示・非表示をstate管理(true:表示 false:非表示)
  // ※modal:現在のstate値 setModal:state値を更新するための関数 false:初期値
  const [modal, setModal] = useState(false)

  return (
    <div>
      {/* ボタンクリック後、modalをtrueに変更 */}
      <button onClick={() => setModal(true)}>Open</button>
      {/* modalがtrueの場合、is-openedクラスを付与 */}
      <div className={`modal__overlay ${modal && "is-opened"}`}>
        <div className="modal__box">
          {/* ボタンクリック後、modalをfalseに変更 */}
          <button className="modal__closeBtn" onClick={() => setModal(false)}>×</button>
          <div>モーダルテキスト</div>
        </div>
      </div>
    </div>
  );
}
.modal__overlay{
  z-index: 999;
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  background: rgba(0,0,0,0.4);
  display: flex;
  align-items: center;
  justify-content: center;
  /* 初期状態は非表示 */
  opacity: 0;
  visibility: hidden;
  /* ゆっくり表示させる */
  transition: opacity .3s, visibility .3s;
}
/* モーダル表示(modalがtrueになったら付与される) */
.is-opened{
  visibility: visible;
  opacity: 1;
}
.modal__box{
  background-color: #fff;
  padding: 30px 20px;
  position: relative;
}
.modal__closeBtn{
  position: absolute;
  top: 0;
  right: 0;
}

ここまでの実装画面
ezgif.com-video-to-gif (4).gif

3.オーバーレイクリックでモーダルを閉じる処理

最後に、オーバーレイをクリックした時にもモーダルを閉じるようにしたいと思います。

<div className={`modal__overlay ${modal && "is-opened"}`}  onClick={() => setModal(false)}>

このように追記することで、オーバーレイクリック後にモーダルを閉じることができますが、これだとモーダルボックス内をクリックした時にも閉じてしまいます。
ezgif.com-video-to-gif (5).gif
そこで、コンポーネントのDOMノードに直接アクセスできるようになるuseRefフックを使用します。

// useRef追加
import React, {useState, useRef} from 'react';

const App = () => {
  // modalRefの定義 ※modalRef.currentでオーバーレイ要素を取得可能に
  const modalRef = useRef()
  const [modal, setModal] = useState(false)

  return (
    <div>
      <button onClick={() => setModal(true)}>Open</button>
      {/* クリックした要素がmodalRef.currentと一致した場合、modalをfalseに変更 */}
      <div className={`modal__overlay ${modal && "is-opened"}`} onClick={e=>{if(modalRef.current === e.target) setModal(false)}} ref={modalRef}>
        <div className="modal__box">
          <button className="modal__closeBtn" onClick={() => setModal(false)}>×</button>
          <div>モーダルテキスト</div>
        </div>
      </div>
    </div>
  );
}

export default App;

完成

ezgif.com-video-to-gif (2).gif

このようにuseState・useRefを使用することで簡単にモーダル実装ができますので、是非お試し下さい!

参考文献

https://chaika.hatenablog.com/entry/2019/12/08/090000
https://ichiki.netlify.app/blog/20191218_react_click_out/

13
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
6