Aswath

Portals are lit 🔥

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">&times;</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.

Tags

Comments

Topics of interest