Reactで createPortalを使用したモーダルを作成する方法

こんばんは。

今日は「Reactで createPortalを使用したモーダルを作成する方法」について説明いたします。

React で createPortal を使用したモーダルを作成する方法は、React のポータル機能を使って、コンポーネントを DOM の別の場所にレンダリングするものです。モーダルは通常、アプリケーションのルート DOM に直接挿入され、通常のコンテンツとは分離されている必要があるため、このようなポータルを使うのが便利です。

以下は、createPortal を用いたシンプルなモーダルの実装例です。

# 基本的なModalコンポーネント
Modal.js というコンポーネントを作成し、ポータルを使ってモーダルを別の DOM ノードにレンダリングします。

```React
// Modal.js
import React, { useEffect } from 'react';
import ReactDOM from 'react-dom';
import './Modal.css'; // スタイリング用のCSSファイル

const Modal = ({ isOpen, onClose, children }) => {
  // モーダルが開いていない場合は何も表示しない
  if (!isOpen) return null;

  // モーダルの外をクリックした時に閉じる処理
  const handleClickOutside = (e) => {
    if (e.target.className === 'modal-overlay') {
      onClose();
    }
  };

  // useEffectでエスケープキーを押した時にモーダルを閉じる
  useEffect(() => {
    const handleEsc = (e) => {
      if (e.key === 'Escape') {
        onClose();
      }
    };
    window.addEventListener('keydown', handleEsc);
    return () => window.removeEventListener('keydown', handleEsc);
  }, [onClose]);

  // ポータルを利用してbodyに直接モーダルを描画する
  return ReactDOM.createPortal(
    <div className="modal-overlay" onClick={handleClickOutside}>
      <div className="modal-content">
        <button className="modal-close" onClick={onClose}>
          Close
        </button>
        {children}
      </div>
    </div>,
    document.getElementById('modal-root') // モーダルを表示するためのDOMノード
  );
};

export default Modal;
```

# モーダル用のスタイリング
次に、Modal.css というCSSファイルを作成し、モーダルのスタイルを定義します。

```css
/* Modal.css */
.modal-overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.5);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 1000;
}

.modal-content {
  background-color: white;
  padding: 20px;
  border-radius: 8px;
  max-width: 500px;
  width: 100%;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
  z-index: 1001;
  position: relative;
}

.modal-close {
  position: absolute;
  top: 10px;
  right: 10px;
  background: none;
  border: none;
  font-size: 16px;
  cursor: pointer;
}
```

# モーダルを使用する親コンポーネント
App.js にて、モーダルの状態管理と使用方法を記述します。

```React
// App.js
import React, { useState } from 'react';
import Modal from './Modal';

function App() {
  const [isModalOpen, setIsModalOpen] = useState(false);

  const openModal = () => setIsModalOpen(true);
  const closeModal = () => setIsModalOpen(false);

  return (
    <div className="App">
      <h1>React Modal with Portal</h1>
      <button onClick={openModal}>Open Modal</button>

      <Modal isOpen={isModalOpen} onClose={closeModal}>
        <h2>This is a Modal</h2>
        <p>Click outside or press Esc to close.</p>
      </Modal>
    </div>
  );
}

export default App;
```

# index.html でモーダル用のノードを追加
React アプリケーションの public/index.html にモーダル用の DOM ノードを追加します。

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>React Modal with Portal</title>
  </head>
  <body>
    <div id="root"></div>
    <div id="modal-root"></div> <!-- モーダル用のポータルルート -->
  </body>
</html>
```

# 動作確認
- 「Open Modal」ボタンをクリックすると、モーダルが表示されます。
- モーダルの外側をクリックするか、エスケープキーを押すとモーダルが閉じます。

この方法で、createPortal を使って React アプリケーションにモーダルを実装することができます。ポータルを使うことで、モーダルが通常の DOM ツリーの構造に影響を与えずに表示されます。

今日は以上です。

ありがとうございました。
よろしくお願いいたします。