Tyotto good!

【サクッとReact】ポータルを使って親コンポーネントの外にある箇所に子コンポーネントをレンダーする

Posted: December 12, 2020

Reactのポータルを用いれば、子コンポーネントを親要素のDOM階層の外のある箇所にレンダリングすることができます。例えばモーダルやダイアログを実装しようとした時にルート要素の直下にコンポーネントを配置する必要がなくなります。
それでは詳しく見ていきましょう。

ポータルの定義

ポータルを作成するには以下のようにします。

ReactDOM.createPortal(child, container)

第一引数でReactのコンポーネントを指定し、第二引数ではDOM要素を指定します。
簡単な例を見ていきましょう。

ダイアログを実装

では、例としてダイアログをポータルを用いて表示していきましょう。
まずダイアログを表示するDOM要素を定義します。以下はReactアプリの最上位に位置するAppコンポーネントとします。そしてダイアログのコンポーネントを持つ親コンポーネントをMenuコンポーネントとします。
Appコンポーネントは以下のようになり、Menuコンポーネントの親要素の外にダイアログを表示するDOM要素が定義されていることがわかります。

import React from "react";
import Menu from "./Menu";

export default function App() {
  return (
    <>
			{/*ダイアログを表示するDOM要素*/}
      <div id="dialog" />
      <div className="App">
        <Menu />
      </div>
    </>
  );
}

では次にダイアログの親コンポーネントであるMenuコンポーネントを実装します。ボタンをクリックした時にダイアログが表示されるように、useStateを用いてダイアログの開閉条件をstateで管理しています。

import React, { useState } from "react";
import Dialog from "./Dialog";

const Menu = () => {
  const [isOpen, setIsOpen] = useState(false);
  const handleClick = () => {
			isOpen ? setIsOpen(false) : setIsOpen(true);
  };
  return (
    <div className="menu">
      <button onClick={handleClick}>show dialog</button>
      {isOpen && <Dialog />}
    </div>
  );
};

export default Menu;

そして、今回のメイントピックであるポータルを用いたダイアログ(Dialog)コンポーネントについて見ていきましょう。
冒頭で説明したReactDOM.createPortal(child, container) 構文を用いて、dialogというidの要素に第一引数で指定した要素をレンダリングしていることがわかります。これでボタンを押すとdialogの表示・非表示を切り替えることができます。

import React from "react";
import ReactDOM from "react-dom";

const Dialog = () => {
  return ReactDOM.createPortal(
    <h2>This is dialog</h2>,
    document.getElementById("dialog")
  );
};

export default Dialog;

ポータルをうまく使いこなして、ダイアログやモーダルの実装に役立ててください!
それでは🙌