javascript - How to render child component outside of its parent component (DOM Hierarchy) - React.js - TagMerge
4How to render child component outside of its parent component (DOM Hierarchy) - React.jsHow to render child component outside of its parent component (DOM Hierarchy) - React.js

How to render child component outside of its parent component (DOM Hierarchy) - React.js

Asked 1 years ago
3
4 answers

After a quick search, I found React Portal approach to render child component html outside of the parent component(DOM Hierarchy).

Component:

import React, { useState } from 'react';
import { Portal } from '../Portal/Portal';


export const FirstPage = () => {

const [value, setValue] = useState('');

return (
    <div id='parent'>
        <input onChange={e => {setValue(e.target.value)}} value={value} />
        <Portal>
            <span id='child'>{value}</span>
        </Portal>
    </div>);
};

Portal.js implementation with React Hooks:

import React, { useEffect, useRef } from "react"
import ReactDOM from 'react-dom';

export const Portal = (props) => {
    const el = useRef(document.createElement('div'));
    useEffect(() => {
        const portal = document.getElementById('portal');
        portal.appendChild(el.current);

        return () => {
            portal.removeChild(el.current);
        };

    }, [props.children]);

    return ReactDOM.createPortal(props.children, el.current);
}

export const PortalDiv = () => <div id='portal'></div>;

App.js:

import React from 'react';
import './App.css';
import { PortalDiv } from './Portal/Portal';
import { FirstPage } from './Pages/FirstPage';

function App() {
  return (
    <div className="App">
      <FirstPage />
      <PortalDiv />
    </div>
  );
}

export default App;

Result:

<div class="App">
    <div id="parent">
        <input value="random text">
    </div>
    <div id="portal">
        <div><span id="child">random text</span></div>
    </div>
</div>

https://github.com/sedpol/react-portal

Source: link

0

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)
Normally, when you return an element from a component’s render method, it’s mounted into the DOM as a child of the nearest parent node:
render() {
  // React mounts a new div and renders the children into it
  return (
    <div>      {this.props.children}
    </div>  );
}
However, sometimes it’s useful to insert a child into a different location in the DOM:
render() {
  // React does *not* create a new div. 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  );
}
This includes event bubbling. An event fired from inside a portal will propagate to ancestors in the containing React tree, even if those elements are not ancestors in the DOM tree. Assuming the following HTML structure:
<html>
  <body>
    <div id="app-root"></div>
    <div id="modal-root"></div>
  </body>
</html>
A Parent component in #app-root would be able to catch an uncaught, bubbling event from the sibling node #modal-root.
// These two containers are siblings in the DOM
const appRoot = document.getElementById('app-root');
const modalRoot = document.getElementById('modal-root');

class Modal extends React.Component {
  constructor(props) {
    super(props);
    this.el = document.createElement('div');
  }

  componentDidMount() {
    // The portal element is inserted in the DOM tree after
    // the Modal's children are mounted, meaning that children
    // will be mounted on a detached DOM node. If a child
    // component requires to be attached to the DOM tree
    // immediately when mounted, for example to measure a
    // DOM node, or uses 'autoFocus' in a descendant, add
    // state to Modal and only render the children when Modal
    // is inserted in the DOM tree.
    modalRoot.appendChild(this.el);
  }

  componentWillUnmount() {
    modalRoot.removeChild(this.el);
  }

  render() {
    return ReactDOM.createPortal(      this.props.children,      this.el    );  }
}

class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {clicks: 0};
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {    // This will fire when the button in Child is clicked,    // updating Parent's state, even though button    // is not direct descendant in the DOM.    this.setState(state => ({      clicks: state.clicks + 1    }));  }
  render() {
    return (
      <div onClick={this.handleClick}>        

Number of clicks: {this.state.clicks}

Open up the browser DevTools to observe that the button is not a child of the div with the onClick handler.

<Modal> <Child /> </Modal> </div> ); } } function Child() { // The click event on this button will bubble up to parent, // because there is no 'onClick' attribute defined return ( <div className="modal"> <button>Click</button> </div> ); } ReactDOM.render(<Parent />, appRoot);

Source: link

0

Creating a portal is simple. All you need is to provide the component you want to render and the DOM element you want to mount the component into, then you simply use the new createPortal method.
ReactDOM.createPortal(componentToRender, elementToRenderInto);
To illustrate this, let's add two divs in the html - one meant for showing notifications to the user and one for mounting our react application.
<body>  
  <div id="notification-box"></div>
  <div id="content"></div>
</body>
Next, we mount our react application as normal to the div with id content.
const App = () => (  
  <div>
    <NotificationBox>
      <Notification/>
    </NotificationBox>
    <Content/>
  </div>
);

ReactDOM.render(<App/>, document.getElementById('content'));
Jumping into the NotificationBox component, we'll see how this is done.
const NotificationBox = ({children}) => {  
  return ReactDOM.createPortal(
    children,
    document.getElementById('notification-box')
  );
};
We can see this by adding an onClick attribute to the App component, then send a component with a button through the portal.
const NotificationWithButton = () => (  
  <button>Click</button>
);

class App extends React.Component {

  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    console.log("click")
  }

  render() {
    return (
      <div  onClick={this.handleClick}>
        <NotificationBox>
          <NotificationWithButton/>
        </NotificationBox>
        <Content/>
      </div>
    )
  }
}

Source: link

0

Say we need to render a child element into a React application. Easy right? That child is mounted to the nearest DOM element and rendered inside of it as a result.
render() {
  return (
    <div>
      // Child to render inside of the div
    </div>
  );
}
The first line of a React application will tell you that an App element is rendered on the document root using ReactDOM. Like this;
ReactDOM.render(<App />, document.getElementById("root"));
We need to place the App element in an HTML file to execute it:
<div id="App"></div>
Same sort of thing with Portals. First thing to creating a Portal is to create a new div element in the HTML file.
<div id="portal"></div>
This div will serve as our target. We’re using #portal as the ID, but it doesn’t have to be that. Any component that gets rendered inside this target div will maintain React’s context. We need to store the div as the value of a variable so we can make use of the Portal component that we’ll create:
const portalRoot = document.getElementById("portal");

Source: link

Recent Questions on javascript

    Programming Languages