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.
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.
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.
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.
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.
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.
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').
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.
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.
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
andReactDOM.createPortal
?
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.)
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
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
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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With