When writing global masks in the past, I usually used fixed positioning, as shown in the following code:

.modal {
  position: fixed;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  z-index:500;
  background: black;
}
Copy the code

So you realize the global mask layer, you control the content in Modal. But there is a problem with this, which is as follows:

You can see that the contents of the popover are not in the layer below the body, but in the nested DOM, which has two drawbacks:

  1. The DOM structure is not elegant enough
  2. The style of the parent component may affect the style of the child component

Here is a real case. My colleague also used the above fixed positioning method to generate the global popover, but found that clicking the button could not change the display of the popover, and then found that a huge weird code was written, which is probably as follows:

<! -- Here is the child component -->
return (
  <button>
    <span>toggle visible</span>
    <modal visible={visible}></modal>
  </button>
)
Copy the code

Then it was found that the crazy button could not control the display and hiding of Modal, because the button seriously affected modal behavior. This is actually a very difficult problem to detect, and you don’t know what weird code the user has written, so consider other ways to avoid the problem. When the user uses Modal, the MODAL DOM is actually mounted under the current component, so think about how you could get around this problem by inserting the DOM directly under the body. Fortunately React provides this capability, React provides a Portal for rendering child nodes to DOM nodes other than the parent component

The Portal is introduced

Portal can render a child component into a DOM tree other than the parent component. It is usually used in scenarios where the child component needs to be removed from the parent component’s container, such as the following scenarios:

  • Dialog Dialog
  • Tooltip Text prompt
  • Popover pop-up
  • Global Loader Loader

Here’s how he uses it:

React.createPortal();
Copy the code

The first argument (child) is any renderable React child, such as an element, string, or fragment. The second argument (container) is a DOM element. Here is a simple example using react. CreatePortal:

const Modal = ({message, visible, onClose, children}) = > {
  if(! visible)return null;
  return ReactDOM.createPortal(
    <div class="modal">
      <span className="message">{message}</span>
      <button onClick={onClose}>Close</button>
    </div>
  , domNode)
}
Copy the code

Although Portal is free of the container constraints of the parent component, it behaves like the normal React component. It can also accept props and context. This is because Portal still exists in the React hierarchy.

Why Portal is needed

Just like the case mentioned at the beginning of the article, we need to use modal popover in a component. In most cases, we can use fixed positioning to make the popover display globally, but in special cases, the Modal popover may display incorrectly. So in this case, if we use the portal approach to directly modal DOM structure out of the parent component container, we can avoid this problem.

const Modal = ({message, isOpen, onClose, children}) = > {
  if(! isOpen)return null;
  return ReactDOM.createPortal(
    <div className="modal">
      <span>{message}</span>
      <button onClick={onClose}>Close</button>
    </div>
  , document.body)
}
function Component() {
  const [open, setOpen] = useState(false)
  return (
    <div className="component">
      <button onClick={()= > setOpen(true)}></button>
      <Modal
        message="Hello World!"
        isOpen={open}
        onClose={()= > setOpen(false)}
      />
    </div>)}Copy the code

This code ensures that this Modal can be at the same level as root, no matter how deep the subcomponents are nested. Using Chrome to examine the DOM structure, you can see the following structure

Precautions for using Portal

When using Portal, it is important to know that although Portal can be placed anywhere in the DOM tree, it behaves the same as the normal React component. Since portal still exists in the React tree and is independent of its location in the DOM tree, features like context remain the same whether its children are portal or not. Here’s a summary of some DOS and don ‘ts.

  1. Event bubbling: An event triggered from within the portal will bubble up to contain ancestors of the React tree, even if those elements are not ancestors in the DOM tree.
  2. Life cycle: Even if an element is created through Portal, the element still has a life cycle such ascomponentDidMount, etc.
  3. Impact scope: Portal only affects the HTML structure and does not affect the React tree structure
  4. Mount nodes: When using Portal, you must define a real DOM node as the mount port for Portal components

conclusion

React Portal is useful when we need to render subcomponents outside of the normal DOM structure without breaking the default behavior of event propagating through the React component tree hierarchy, which is useful in rendering things like pop-ups and hints

Welcome to pay attention to “front-end learn well”, front-end learning do not get lost or add wechat SSDWBObo, exchange and learn together