Recently I was introduced to Reacts' createPortal API, which was nothing short of amazing.
Let me share my experiences with it!
Being a professional Ember developer, my love towards React has never faded away. React with its' component oriented architecture boosts productivity, ensures stable code and is backed up with strong community.
I don't wanna bore you, with this sort of things that you(probably many Web devs) hear in routine.
I think, Its' time to get our hands dirty with Portals 🔥
'Portals provide a first-class way to render children into a DOM node that exists outside the DOM hierarchy of the parent component'
Generally, not everyone in the world can understand the definition in the official docs in a single glance!, atleast NOT ME! (jus kidding, Reacts' docs on Portals is more beginner friendly peeps, go check it out)
So i decided to have a practical approach with it:
As stated in the definition, Portals provide a way to render children of a react component somewhere else in the DOM, not in the same hierarchy!
As soon i realised it, i was ended up with nothing but questions.
OMG what about the event bubbling? and many…
Being a professional ember developer, i have used Ember Wormhole, it is an addon probably does the similar work of Portals in Ember.
I kept digging more about Portals. One thing i explored is its' use-case in Modal Dialogs.
I built a modal component with bootstrap(overriding some of bootstrap styles) in react similar to this 👇
//Modal.js
import React from "react";
import ReactDOM from "react-dom";
export default class Modal extends React.Component {
onClose = e => {
this.props.onClose && this.props.onClose(e);
};
render() {
let modal = (
<div
class="modal fade"
id="exampleModalCenter"
>
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLongTitle">
Modal title
</h5>
<button
type="button"
class="close"
>
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">...</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-secondary"
>
Close
</button>
<button type="button" class="btn btn-primary">
Save changes
</button>
</div>
</div>
</div>
</div>
);
return (modal);
}
}
I rendered it as a child to App 👇
//App.js
import React from "react";
import Modal from "./Modal-Compo";
export default class App extends React.Component {
onClose = e => {
this.props.onClose && this.props.onClose(e);
};
render() {
let alignCenter = {
display: "flex",
alignItems: "center",
justifyCenter: "center",
height: "200px",
overflow: "hidden",
width: "50%",
margin: "auto",
marginTop: "10%"
};
return (
<div style={alignCenter}>
<p style={{ height: "100%", margin: "0" }}>
//some random 100 lines
</p>
<Modal onClose={this.onClose}/>
</div>
)
}
}
Atlast rendered the App component in the root element 👇
//Index.js
import React from "react";
import ReactDOM from "react-dom";
import "bootstrap/dist/css/bootstrap.min.css";
import "jquery/dist/jquery.min.js";
import "bootstrap/dist/js/bootstrap.min.js";
import App from "./components/App";
import "./styles.css";
function WhatAreModals() {
return (
<div style={{ height: "100vh" }} className="App">
<App />
<button
type="button"
className="btn btn-primary"
data-toggle="modal"
data-target="#exampleModalCenter"
>
Launch demo modal
</button>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<WhatAreModals />, rootElement);
Finally my prototype was ready 😃
When i clicked the Launch demo modal CTA, this happened (oopsy) 😕
The culprit is the App component styled 'overflow:hidden', as in our case the Modal component is rendered as a child of App whose overflow is hidden, our Modal never shows up 😩
Here is where the life saver Portal comes in 🔥
I just made a tweak in my Modal component and the index.html(created another root element for Modal to be rendered)
//index.html
<div id="root"></div>
<div id="modal-root"></div> //added this
Rendered Modal in Portal, changed return statement by implementing createPortal
//Modal.js
ReactDOM.createPortal(modal, document.getElementById("modal-root"));
It worked seamlessly,
The problem was solved by breaking the Modal component out of the container, out of the hierarchy.
But suddenly i got into a confusion, as the hierarchy is broken i doubted whether event bubbling will occur? (I think, Many will question this!).
I went on digging deeper 😁
Native DOM Snapshot:
React DOM:
Finally, i was satisfied seeing this, probably many would be 😌
From the snapshots, we come to know that the hierarchy is unaltered in Reacts' Virtual DOM, so event bubbling will happen with ease.
Portals can be widely used 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 tooltips.
I feel this post would've satisfied you on Reacts' createPortal API, if yes, feel free to share this with your colleague web devs as well.