Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use ReactDOM.createPortal() in React 16?

I'm using React 16 and need portals, but am not able to find any documentation on this feature. Does anyone know how to use this yet?

https://github.com/facebook/react/pull/10675

Thanks for any advice.

like image 381
Slbox Avatar asked Sep 24 '17 18:09

Slbox


People also ask

What is ReactDOM createPortal?

Portals provide a first-class way to render children into a DOM node that exists outside the DOM hierarchy of the parent component. ReactDOM. createPortal(child, container) The first argument ( child ) is any renderable React child, such as an element, string, or fragment.

How do I import ReactDOM into React?

import ReactDOM from 'react-dom'; or if you're using ES5 you can just do: var ReactDOM = require('react-dom'); and then you can use ReactDOM.

Which component do we have to pass to the ReactDOM render () method?

render() The first argument is the element or component we want to render, and the second argument is the HTML element (the target node) to which we want to append it. Generally, when we create our project with create-react-app , it gives us a div with the id of a root inside index.

Why is ReactDOM not part of React library?

The reason React and ReactDOM were split into two libraries was due to the arrival of React Native. React contains functionality utilised in web and mobile apps. ReactDOM functionality is utilised only in web apps.

How do I create a portal in ReactJS?

Portals are created by calling the createPortal method inside the render method of your component. renderPortal should return contents to be rendered inside the portal, while portalEl is an external DOM element that will receive the content. Someone recently twitted that info on portals can be found in React tests.

How to import reactdom from React-DOM?

ReactDOM. If you load React from a <script> tag, these top-level APIs are available on the ReactDOM global. If you use ES6 with npm, you can write import ReactDOM from 'react-dom'. If you use ES5 with npm, you can write var ReactDOM = require ('react-dom').

What is the use case for a portal in reactdom?

It renders the children into `domNode`. // `domNode` is any valid DOM node, regardless of its location in the DOM. return ReactDOM.createPortal( this.props.children, domNode ); } A typical use case for portals is when a parent component has an overflow: hidden or z-index style, but you need the child to visually “break out” of its container.

What is React-DOM package used for?

Overview The react-dom package provides DOM-specific methods that can be used at the top level of your app and as an escape hatch to get outside of the React model if you need to. Most of your components should not need to use this module.


4 Answers

React v16 has just released a couple of hours ago (Yay!!) which officially supports Portal.

What is Portal? Since How long has it been there?

Portals provide a first-class way to render children into a DOM node that exists outside the DOM hierarchy of the parent component.

Portal is not new concept in the react community. Many libraries are available that supports this kind of functionality. e.g react-portal and react-gateway.

What happens when rendering any react app?

Generally, when rendering any React application, a single DOM element is used to render the whole React tree.

class HelloReact extends React.Component {
   render() {
       return (
          <h1>Hello React</h1>
       );
   }
}

ReactDOM.render(<HelloReact />, document.getElementById('root'));

As you can see we are rendering our react component into a DOM element having id root.

What is Portal and why is it needed? Why is it there?

Portals are a way to render React children outside the main DOM hierarchy of the parent component without losing the react context. I'm emphasizing on it because very popular libraries like react-router, redux heavily uses the react context. So context availability when using Portal is very helpful.

As per the react docs,

A typical use case for portals is when a parent component has an overflow: hidden or z-index style, but you need the child to visually "break out" of its container. For example, dialogs, hovercards, and tooltip.

So, with portals, you can render a parallel react tree onto another DOM node when needed. Even though it is rendered in the different DOM node, parent component can catch the uncaught events. See this codepen provided in the docs itself.

The below example should give your more idea:

// index.html
<html>
    <body>
        <div id="root"></div>
        <div id="another-root"></div>
    </body>
</html>

// index.jsx
const mainContainer = document.getElementById('root');
const portalContainer = document.getElementById('another-root');

class HelloFromPortal extends React.Component {
    render() {
         return (
           <h1>I am rendered through a Portal.</h1>
         );
    }
}

class HelloReact extends React.Component {
    render() {
        return (
             <div>
                 <h1>Hello World</h1>
                 { ReactDOM.createPortal(<HelloFromPortal />, portalContainer) }
             </div>
        );
    }
}

ReactDOM.render(<HelloReact />, mainContainer);

https://codesandbox.io/s/62rvxkonnw

You can use devtools inspect element and see that <h1>I am rendered through a Portal.</h1> is rendered inside #another-root tag, whereas <h1>Hello World</h1> is rendered inside #root tag.

Hope this helps :)

Update: To answer @PhillipMunin's comment.

What is the different between ReactDOM.render and ReactDOM.createPortal?

  1. Even though the component rendered through the portal is rendered somewhere else (Outside the current container root), it remains present as the child of the same parent component. (Who invoked the ReactDOM.createPortal) So any events on the child are propagated to the parent. (Ofc, This doesn't work if you manually stop the propagation of the event.)

  2. Same context is accessible inside the component rendered through a portal. But not in the case when we do ReactDOM.render directly.

I've created another demo to illustrate my point. https://codesandbox.io/s/42x771ykwx

like image 124
Hardik Modha Avatar answered Oct 13 '22 07:10

Hardik Modha


I think we can achieve same feature by creating an external dom node outside 'root' element

node = document.createElement('div')
document.body.appendChild(node)
ReactDOM.render(<Modal {...props} />,node)

Let's say we are creating a modal view, we can create a wrapper for the same

import React, { useEffect } from 'react'
import ReactDOM from 'react-dom'
import Modal from './Modal'
let node = null
const ModalWrapper = (props) =>{
    useEffect(()=>{
        node && ReactDOM.render(<Modal {...props} />,node)
    })
    useEffect(()=>{
        node = document.createElement('div')
        document.body.appendChild(node)
        ReactDOM.render(<Modal {...props} />,node)
    },[])
    return(
        <script />
    )
}

Here is an example Create Modal with React Portal and React Hooks from scratch without external library

React-modal with portal

like image 27
OnlyJS Avatar answered Oct 13 '22 07:10

OnlyJS


For anyone wondering, here is how I implemented my own custom Portal component in Typescript

    import React from 'react'
    import ReactDOM from 'react-dom'

    const Portal: React.FC<PortalProps> = (props) => {
        return ReactDOM.createPortal(props.children, props.target)
    }

    export interface PortalProps {
        target: Element;
        children: React.ReactNode;
    }

    export default Portal
like image 4
devaent Avatar answered Oct 13 '22 05:10

devaent


Portals are created by calling the createPortal method inside the render method of your component.

render() {
  return (
    <div>
      {ReactDOM.createPortal(this.renderPortal(), this.props.portalEl)}
    </div>
  )
}

renderPortal should return contents to be rendered inside the portal, while portalEl is an external DOM element that will receive the content.

Someone recently twitted that info on portals can be found in React tests.

like image 1
Marko Avatar answered Oct 13 '22 07:10

Marko