Multiple Elements gets appended instead of one in React Modal

Asked
Active3 hr before
Viewed126 times

11 Answers

appendedinsteadmodalelementsreactmultiple
90%

I've written a library to help with this. I avoid the DOM insertion hacks used by Portal strategies out there and instead make use of context based registries to pass along components from a source to a target.,My implementation makes use of the standard React render cycles. The components that you teleport/inject/transport don't cause a double render cycle on the target - everything happens synchronously.,The fundamental problem here is that in React you're only allowed to mount component to its parent, which is not always the desired behavior. But how to address this issue?

At react conf 2015, Ryan Florence demonstrated using portals. Here's how you can create a simple Portal component...

var Portal = React.createClass({
  render: () => null,
  portalElement: null,
  componentDidMount() {
    var p = this.props.portalId && document.getElementById(this.props.portalId);
    if (!p) {
      var p = document.createElement('div');
      p.id = this.props.portalId;
      document.body.appendChild(p);
    }
    this.portalElement = p;
    this.componentDidUpdate();
  },
  componentWillUnmount() {
    document.body.removeChild(this.portalElement);
  },
  componentDidUpdate() {
    React.render(<div {...this.props}>{this.props.children}</div>, this.portalElement);
  }
});

and then everything you can normally do in React you can do inside of the portal...

    <Portal className="DialogGroup">
       <ReactCSSTransitionGroup transitionName="Dialog-anim">
         { activeDialog === 1 && 
            <div key="0" className="Dialog">
              This is an animated dialog
            </div> }
       </ReactCSSTransitionGroup>
    </Portal> 
load more v
88%

The problem is that each form is given the same props, so they are treated as the same form. In your render function, you create multiple Buttons and CollectionCreateForms:

<Button type="primary" onClick={this.showModal}>New Collection</Button>
<CollectionCreateForm
  ref={this.saveFormRef}
  visible={this.state.visible}
  onCancel={this.handleCancel}
  onCreate={this.handleCreate}
/>
// repeated...
load more v
72%

Consequently, it’s quite common that React App Components get very deeply nested. We are talking dozens of levels deep, and often more. So if one of those deeply nested Components needs to show a modal, it’s going to face some serious CSS issues.,Once the <App/> Component gets rendered to the DOM, the actual <div> element with id “#root” gets the entire React App rendered inside it.,…with the actual Modal Component looking like:

  1. In index.html, inside the <body> tag:
<body>
   <noscript>
      You need to enable JavaScript to run this app.
   </noscript>

   <div id="root"></div>

   <div id="modal"></div> . //ADD THIS

</body>

</html>
load more v
65%

A Parent component in #app-root would be able to catch an uncaught, bubbling event from the sibling node #modal-root.,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:,Catching an event bubbling up from a portal in a parent component allows the development of more flexible abstractions that are not inherently reliant on portals. For example, if you render a <Modal /> component, the parent can capture its events regardless of whether it’s implemented using portals.

ReactDOM.createPortal(child, container)
load more v
75%

We will attach a ref to the root DOM element. Inside componentDidMount, we will get a reference to it so we can pass it to the jQuery plugin.,This way, Chosen will know to update its DOM element when the <select> children managed by React change.,To demonstrate this, let’s sketch out a wrapper for a generic jQuery plugin.

class SomePlugin extends React.Component {
  componentDidMount() {
    this.$el = $(this.el);    this.$el.somePlugin();  }

  componentWillUnmount() {
    this.$el.somePlugin('destroy');  }

  render() {
    return <div ref={el => this.el = el} />;  }
}
load more v
40%

The only required prop for the modal object is isOpen, which indicates whether the modal should be displayed. The following is an example of using react-modal specifying all the possible props and options:,By default, the modal portal will be appended to the document's body. You can choose a different parent element by providing a function to the parentSelector prop that returns the element to be used:,You can use ref callbacks to get the overlay and content DOM nodes directly:

$ npm install react - modal
$ yarn add react - modal
load more v
22%

Here are the basic requirements of a simple react modal:,Create a ModalTrigger component, it’s same as Modal component for now.,I’ve used lorem ipsum as a filler text. You can use any text or image as placeholder. Or you can generate lorem ipsum within the VS Code. To get a lorem ipsum text in VS Code, type lorem, suggestion for lorem ipsum will appear. Expand it with TAB key. The suggestion is provided by emmet plugin (comes built-in).

Set up the application with create-react-app

npx create - rect - app react - modal
load more v
60%

What’s the “react” way to trigger a modal when a button is clicked?,Contrast this to jQuery where you might show and hide an element by toggling a CSS class, or maybe adding and removing it from the DOM.,Then the modal will wait for its “Close” button to be clicked.

import React from 'react';
import PropTypes from 'prop-types';

class Modal extends React.Component {
  render() {
    // Render nothing if the "show" prop is false
    if(!this.props.show) {
      return null;
    }

    // The gray background
    const backdropStyle = {
      position: 'fixed',
      top: 0,
      bottom: 0,
      left: 0,
      right: 0,
      backgroundColor: 'rgba(0,0,0,0.3)',
      padding: 50
    };

    // The modal "window"
    const modalStyle = {
      backgroundColor: '#fff',
      borderRadius: 5,
      maxWidth: 500,
      minHeight: 300,
      margin: '0 auto',
      padding: 30
    };

    return (
      <div className="backdrop" style={{backdropStyle}}>
        <div className="modal" style={{modalStyle}}>
          {this.props.children}

          <div className="footer">
            <button onClick={this.props.onClose}>
              Close
            </button>
          </div>
        </div>
      </div>
    );
  }
}

Modal.propTypes = {
  onClose: PropTypes.func.isRequired,
  show: PropTypes.bool,
  children: PropTypes.node
};

export default Modal;
load more v
48%

Building modal dialogs in React is a challenge due to their architectural and accessibility complications. However, there is an easy solution.if(typeof __ez_fad_position != 'undefined'){__ez_fad_position('div-gpt-ad-upmostly_com-box-3-0')};,React’s design and architectural best practices mean modal dialogs require more effort than throwing together a simple component. ,♿️Conforms to WAI-ARIA accessibility modal dialog specifications

import {
   useState
} from 'react';

const useModal = () => {
   const [isShowing, setIsShowing] = useState(false);

   function toggle() {
      setIsShowing(!isShowing);
   }

   return {
      isShowing,
      toggle,
   }
};

export default useModal;
load more v
23%

A modal has a few basic sections: the Header, the Title, the Body, and the Footer. These sections will hold the content that we need to display. Here's an example displaying a basic modal using these components.,To get started with using Bootstrap in your React application, you need to install the react-bootstrap package from npm along with the bootstrap v4 package. You will need to install regular Bootstrap for the CSS.,Installing React-Bootstrap

1 yarn add react - bootstrap bootstrap
2 # or
3n pm i react - bootstrap bootstrap
load more v
90%

One common pattern in React apps is that you want to return multiple components in one element. Using fragments is the way to do this. When you wrap components inside a fragment, you do not add an extra DOM node outside the components that you want to render.,It is easy to use fragments, we just put:

It is easy to use fragments, we just put:

return ( <React.Fragment>
   <ComponentA />
   <ComponentB />
   <ComponentC />
</React.Fragment>);

Other "appended-instead" queries related to "Multiple Elements gets appended instead of one in React Modal"