ReactDOM portalとは？

<h2>RactDOM portal</h2>
Portal機能は、親コンポーネントのDOM階層構造の外側にあるDOMノードに子をレンダリングする機能を提供します。
普通は自分を囲んでいる親の下で描かれます。しかし、視覚的に子を飛び出して出るように見せなければならない場合があります。

<h2>Portal　使用前</h2>

```react:Dialog.jsx
import React from 'react'
import { useState } from 'react'

export default function Dialog(props) {
    const [isOpen, setIsOpen] = useState(false);
    return (
    <>
        <button
        style={{
            position: 'absolute',
            left: 100,
        }}
        onClick={()=> setIsOpen(true)}>Open</button>
        
        {isOpen && <div
        style={{
            position: "absolute",
            zIndex: 99,
            top: "50%",
            left: "50%",
            transform: "translate(-50%, -50%)",
            border: "1px solid black",
            padding: 24,
            backgroundColor: "white",
        }}
        >
            { typeof props.title === "string" ? (
            <h1>{props.title}</h1> 
            ) :  (props.title)} 
            
            { typeof props.description === "string" ? (
            <h1>{props.description}</h1> 
            ) :  (props.description)} 

            { typeof props.button === "string" ? (
            <button style={{backgroundColor:"red", color: "wthie"}}onClick={()=> setIsOpen(false)}>{props.button}</button>
            ) :  (
                <div onClick={()=>setIsOpen(false)}>
                {props.button}
                </div>
            )} 
            </div>
        }
    {isOpen && <div style={{
        position: "fixed",
        top: 0,
        left: 0,
        bottom: 0,
        right: 0,
        backgroundColor: "lightgray"
    }}/>}
    </>
    );
}
```
Dialog.jsxは isOpen State値によって、ボタンの表示状態が変わるし、
Propsを受け取って、dialogに出力する内容を決めます。
```react:ThankyouDialog.jsx
import React from 'react'
import Dialog from './Dialog'

export default function ThankyouDialog() {
  return (
    <Dialog 
        title={<h1 style={{color: `red`}}>Sorry</h1>}
        description="Sorry My Fault!!"
        button={<button style={{backgroundColor: "red", color:"white"}}>close</button>}
        />
  )
}
```
ThankyouDialog.jsxはDialog.jsxにDialogに出力する内容をPropsにて渡します。
```react:Example.jsx
import React from 'react'
import { createPortal } from 'react-dom'
import ThankyouDialog from './ThankyouDialog'

export default function Example() {
    return (
        <div>
            <ThankyouDialog />
            <div style={{ position: "absolute "}}>
                <button>hahah</button>
            </div>
        </div>
    )
}
```
Example.jsxはThankyouDialogコンポーネントとhahahaボタンを出力しています。

下は、openボタンをクリックした画面です。
ダイアログがz-index基準で既存のものをすべて上書きしなければならないが、後ろにあるものが上位を占めるためhahaが見えてしまいます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3097775/3d949a40-7c99-92e5-42c2-d168707b2c5f.png)

hahahaを非表示にするには、Example.jsxのThankyouDialogをhahaha Divの次に配置させれば、hahahaボタンが非表示になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3097775/02385631-8560-ecaa-7077-7f29098e7b87.png)
上記の場合は、子供たちが同じ親の下にいるため、位置を変えることで被せることができますが、 
もしレイヤーがあるコンポーネントの中に中に入っていると、レイヤーが順次持っているUIスタックを離れることが不可能になります。

<h2>Portal　使用方法</h2>

index.htmlにidをportalを持つdivを追加します。
```index.html
  // 省略
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div> 
    <div id="portal"></div> 
  // 省略
  </body>
</html>
```
```Example.jsx
import React from 'react'
import { createPortal } from 'react-dom'
import ThankyouDialog from './ThankyouDialog'

const Portal = (props) => {
    return createPortal(props.children, document.getElementById('portal'));
}

export default function Example() {
    return (
        <div>
            <Portal>
                <ThankyouDialog />
            </Portal>
            <div style={{ position: "absolute "}}>
                <button>hahah</button>
            </div>
        </div>
    )
}
```
createPortal(child, container)を使って、外側にあるDOMノードに子をレンダリングします。
上記だと、<ThankyouDialog>が子ともになり、index.htmlのportal divがcontainerになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3097775/c35edd8a-18d6-3e39-d74a-c413b538796b.png)

開発者モードで確認したElement！ThankyouDialogがportal divにレンダリングされていることがわかります！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3097775/cf84fd78-3acd-7431-1f2f-55892a96a4d9.png)
<h2>portal event</h2>

```Example.jsx
import React from 'react'
import { createPortal } from 'react-dom'
import ThankyouDialog from './ThankyouDialog'

const Portal = (props) => {
    return createPortal(props.children, document.getElementById('portal'));
}

export default function Example() {
    return (
        <div onClick={() => console.log('div')}>
            <Portal>
                <ThankyouDialog />
            </Portal>
            <div style={{ position: "absolute "}}>
                <button>hahah</button>
            </div>
        </div>
    )
}
```
divにeventとしてonClickを定義しています。
hahahaを押下すると、もちろんdivログが出力されますが、ThankyouDialogはindex.htmlのrootではない、portalタグに入っているため、portalでEventが起きてもrootには伝わると思われますが
Reactでは意図的にPortalにあるElementでもそこで発生するEventはrootにも伝えています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3097775/d40a8a18-5a0f-5ac6-dcc8-7647087c46e5.png)