# React Portal, 在 root 以外掛載元件 ###### tags: `React` `Portal` `ReactDom` > React 提供了 Portal 方法,讓 children 可以 render 到 parent component DOM 樹以外的 DOM 節點。 像是以下範例 ``` ... return ( <React.Fragment> <MyModal /> <MyForm /> </React.Fragment> ) ... ``` 大至會產出以下 Real DOM ``` <section> <h2>Some Other content</h2> <div class='my-modal'> <h2>My Modal Title</h2> </div> <form> <label>Username</label> <input type='text' /> </form> </section> ``` 但當 Modal 元件位置越來越深時,就會產生一些問題,在 HTML 語意上 Modal 作用使覆蓋整個頁面,嵌套在在某個元件中是較不理想的! ### 要如何改變掛載的節點呢? 到 public/index.html 找到 id 為 root 的 DOM,並在前方新增 `modal-root` & `backdrop-root` id ``` <body> <noscript>You need to enable JavaScript to run this app.</noscript> <div id="backdrop-root"></div> <div id="modal-root"></div> <div id="root"></div> ... </body> ``` 到 ErrorModal 元件中有 `backdrop` 以及 `modal` 兩個平行的 div ``` const ErrorModal = (props) => { return ( <> <div className={classes.backdrop} /> <Card className={classes.modal}> .... </Card> </> ); }; export default ErrorModal; ``` 將 `backdrop` 以及 `modal` 分開定義變數 #### 並且使用 `ReactDOM.createPortal()` 掛載至指定 DOM ``` // ReactDOM import ReactDOM from "react-dom"; // Backdrop const Backdrop = (props) => { return <div className={classes.backdrop} />; }; // ModalOverlay const ModalOverlay = (props) => { return ( <Card className={classes.modal}> ... </Card> ); }; // 掛載節點 const ErrorModal = (props) => { return ( <> {ReactDOM.createPortal( <Backdrop />, document.getElementById("backdrop-root") )} {ReactDOM.createPortal( <ModalOverlay />, document.getElementById("modal-root") )} </> ); }; export default ErrorModal; ``` 到 chrome 觀察 可以發現剛剛新增的兩個節點裡面都有指定的元件在內了!  觀察入口 index.js,使用 `ReactDOM.render` 訪法將 JSX 渲染至 root DOM 上,而 `React.createPortal` 也是使用差不多的邏輯 ``` import App from './App'; ReactDOM.render(<App />, document.getElementById('root')); ``` :::info 差別是我們不是將 ErrorModal 元件另外在另一個 DOM 上做渲染,而是改變已渲染完成的元件掛載的節點。 :::
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up