createPortal は、React が提供する関数で、React コンポーネントを現在のコンポーネント階層の外に描画したいときに使うものである。
つまり、コンポーネントとしては①の階層(場所)にいるけど、②の階層(場所)として振る舞うことができる。
少し具体的に説明すると、divタグのclassNameがstartというところに位置しているが、createPortalを使用することでdivタグのclassNameがendというところに位置しているように振る舞うことができるというもの。
コードを用いて説明する。
createPortalは以下のように定義する。
import { createPortal } from "react-dom";
const ModelPortal = ({children}) => {
const target = document.querySelector(".container.start"); ここで対象のDOMを取得。
return createPortal(children,target);
};
そして以下のように定義したタグで囲むことで使うことが出来る。
<ModalPortal>
<Modal handleCloseClick={() => setModalOpen(false)} />
</ModalPortal>
今回の例で行くと、classNameが”contain start”のDOMを抽出し、targetとする。
そして、createPortalの第1引数にchildren、第2引数にtargetとすることで、今回定義したModelPortalに挟まれたDOMをclassNameが”contain start”のDOMの子要素とすることができる。
これは以下のような場面で利用できる。
import { useState } from "react";
import { createPortal } from "react-dom";
import Modal from "./components/Modal";
const ModalPortal = ({ children }) => {
const target = document.querySelector(".container.end");
return createPortal(children, target);
};
const Example = () => {
const [modalOpen, setModalOpen] = useState(false);
return (
<div onClick={() => console.log('空のdiv')}>
<div className="container end" onClick={() => console.log('container')} />
<button
type="button"
onClick={() => setModalOpen(true)}
disabled={modalOpen}
>
モーダルを表示する
</button>
{modalOpen && (
<ModalPortal>
<Modal handleCloseClick={() => setModalOpen(false)} />
</ModalPortal>
)}
</div>
);
};
export default Example;
今回の例でいくと、ModalPortalが位置しているところはclassName=”container end”の場所と離れているが、modalOpenがtrueの時のみ、className=”container end”のdivタグの子要素として振る舞うといった仕様。
このように状況によって親要素を変えることができるのがcreatePortal。