React portals let you render a React child into a different DOM element, somewhere totally separate on the page.
I want to do the reverse: I want to render a DOM element once, elsewhere on the page, and then pull it into my React DOM output depending on my react tree.
The specific use case for this is Monaco Editor. It's a complex component, which is expensive to render from scratch, but cheap to update. In my application, the editor appears/disappears as users open/close different content. That means React creates the component from scratch each time new content is opened, and the delay to create a new editor makes that action a slower than I'd like.
I'd like to render it once, hide it somewhere, and then show it in the right place in my DOM when & where it's needed. I know that I only need one instance at any time.
A React Portal can be created using the createPortal function imported from react-dom . It takes two arguments: content : any valid renderable React element. containerElement : a valid DOM element to which we can append the content.
Portals provide a first-class way to render children into a DOM node that exists outside the DOM hierarchy of the parent component. The first argument ( child ) is any renderable React child, such as an element, string, or fragment. The second argument ( container ) is a DOM element.
We mainly need portals when a React parent component has a hidden value of overflow property(overflow: hidden) or z-index style, and we need a child component to openly come out of the current tree hierarchy.
In the end I built a library to do it myself: https://github.com/httptoolkit/react-reverse-portal.
Render your content in one place, once, and pass it around and insert it into the DOM somewhere else without rerendering.
Example:
import * as portals from 'react-reverse-portal';
const MyComponent = (props) => {
const portalNode = React.useMemo(() => portals.createPortalNode());
return <div>
<portals.InPortal node={portalNode}>
<MyExpensiveComponent
myProp={"defaultValue"}
/>
</portals.InPortal>
{ props.componentToShow === 'component-a'
? <ComponentA portalNode={portalNode} />
: <ComponentB portalNode={portalNode} /> }
</div>;
}
const ComponentA = (props) => {
return <div>
A:
<portals.OutPortal node={props.portalNode} />
</div>;
}
const ComponentB = (props) => {
return <div>
B:
<portals.OutPortal
node={props.portalNode}
myProp={"newValue"}
myOtherProp={123}
/>
</div>;
}
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