React Portals, And how to use them (Next js and CRA)

Hi everyone.
In this post I want to show you how to work with react portals.
First I'm gonna create one then render some elements, such as modals, notifications, etc...

1. Create create-react-app

// Create a new app
npx create-react-app my-app

// Run the created app
cd my-app
yarn start

// http://localhost:3000

2.Edit index.html and add you portal

<!DOCTYPE html>
<html lang="en">
   <head>
      <meta charset="utf-8" />
      <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
      <meta name="viewport" content="width=device-width, initial-scale=1" />
      <meta name="theme-color" content="#000000" />
      <meta
         name="description"
         content="Web site created using create-react-app"
      />
      <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
      <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
      <title>React App</title>
   </head>
   <body>
      <noscript>You need to enable JavaScript to run this app.</noscript>
      <div id="root"></div>
      <--- Your portal here --->
      <div id="myportal"></div>
   </body>
</html>

3.Create HOC folder and inside it create Portal.js
(src/HOC/Portal.js)

import ReactDOM from "react-dom"

const Portal = (Component) => (props) => {
   return ReactDOM.createPortal(
      <Component {...props} />,
      document.getElementById("myportal")
   )
}

export default Portal

4.Now let's create our Component
This component will render in "myportal" element
(src/components/MyComponent.js)

import Portal from "./../HOC/Portal"

const MyComponent = () => {
    return <div>This component will be rendered in myportal</div>
}

export default Portal(MyComponent) // trick is here

So, as you can see I wrapped MyComponent in Portal component, Portal will render everything that is wrapped in it. :)

create-react-app is done. Let's go to Next Js

1.Create next app

// Create a new app
npx create-next-app my-app

// Run the created app
cd my-app
yarn dev

// http://localhost:3000

In Next.Js we don't have any html file so we can't add div manually, But we have other choice.

2.Let's create _document.js file in pages folder
(pages/_document.js)

import Document, { Html, Head, Main, NextScript } from "next/document"

export default class MyDocument extends Document {
   render() {
      return (
         <Html>
            <Head />
            <body>
               <Main />
               <div id='myportal' /> //out portal is here...
               <NextScript />
            </body>
         </Html>
      )
   }
}

So now we got our portal element.

3.Time to create our HOC
(HOC/Portal.js)

import { useEffect, useState } from "react"
import { createPortal } from "react-dom"

const Portal= ({ children }) => {
   const [mounted, setMounted] = useState(false)

   useEffect(() => {
      setMounted(true)

      return () => setMounted(false)
   }, [])

   return mounted
      ? createPortal(children, 
        document.querySelector("#myportal"))
      : null
}

export default Portal

Now to use it we will put our components as a child in Portal component and return it as a children.

4.For example in index.js/ Home page
(pages/index.js)

function Home() {
   return (
      <div>
         <Head>
         </Head>

         <Portal>
            <MyComponent /> //our component which will 
                            //be rendered inside myportal
         </Portal>
      </div>
   )
}

export default Home

So you are all done my friends! Hope you enjoyed this post

39