user6761897
user6761897

Reputation:

Rendering a modal in React

I'm trying to trap an onclick method on a React component to create a React Modal. I've added react-overlay as a dependency and added it to my file.

import Modal from 'react-overlays';

This is the anchor element,

<a href="#" onClick={this.handleClick} data-id={image.id}>

This is the handleclick method,

handleClick(event) {
    event.preventDefault();
    let mediaId = event.currentTarget.attributes['data-id'].value;
    this.setState({ overlay: <Modal show={this.state.showModal} onHide={this.close} mediaId={mediaId}/> });
  }

I get the following error,

Warning: React.createElement: type should not be null, undefined, boolean, or number. It should be a string (for DOM elements) or a ReactClass (for composite components).
Uncaught Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined.(…)

Upvotes: 1

Views: 5231

Answers (4)

user12575927
user12575927

Reputation: 357

In case anyone still has an issue with this, a modern approach is to build the modal using React hooks. as shown below

import React from 'react';
import './modal.css';
import FontAwesome from 'react-fontawesome';

const Modal = (props) => {
  const { closeModal } = props;

  const closeicon = () => (
    <FontAwesome
    name="times"
    onClick={closeModal}
    style={{
      color: '#000000',
      padding: '10px',
      cursor: 'pointer',
      backgroundColor: 'transparent',
      border: 0,
      position: 'absolute',
      top: '0.3rem',
      right: '0.5rem',
    }}
    />
  );

  return (
    <div className="overlay">
      <div className="content">
        { closeicon() }
        {props.children}
      </div>
    </div>
  );
};


export default Modal;

The css is as shown below

.overlay {
    position: fixed;
    display: block; 
    overflow: auto; 
    width: 100%; 
    height: 100%; 
    top: 0; 
    left: 0;
    right: 0;
    bottom: 0;
    background-color: rgba(0,0,0,0.5); 
    z-index: 999; 
    cursor: pointer;
  }

.content {
        margin: 15% auto;
        background-color: white;
        border-radius: 0.25rem;
        width: 50vw;
        padding: 2rem;
        position: relative;
  }


So you can use the modal component like this

 const [status, setStatus] = useState(false);

//this button will trigger the modal

<button onClick={() => setStatus(true)}>Open Modal</button>


{
status && (
<Modal closeModal={() => setStatus(false)}><p>hello worls</p></Modal>
         )
}


No need to worry about responsiveness It's been taken care of in the styling.

For further explanation, you can check this link https://dev.to/adeyemiadekore2/how-to-build-a-reusable-and-responsive-modal-in-react-from-scratch-1o0f

Upvotes: 0

fckt
fckt

Reputation: 571

Looks like you're importing undefined..

Also, take a look at https://github.com/fckt/react-layer-stack. This is universal and clean way to solve the "modal problem" in React. Demo - https://fckt.github.io/react-layer-stack/

Upvotes: 0

squall3d
squall3d

Reputation: 1757

Your state should contain information that allows you to render the modal, but not the modal itself.

It's highly unusually to store components in state.

Try this:

  1. Store a flag in your state to indicate whether the modal should be shown.
  2. Set the flag in handleClick()
  3. In render(), render the modal if the flag is set.

Let me know if you need an example.

Upvotes: 0

gustavaa
gustavaa

Reputation: 41

I recently had this problem and got around it by creating a Modal-component.

import Modal from 'react-modal'


export default class CustomModal extends React.Component {

    constructor () {
        super();
        this.openModal = this.openModal.bind(this);
        this.closeModal = this.closeModal.bind(this);
        this.state = {
            open: false
        }
    }

    openModal () { this.setState(
        {open: true});
        $(function(){
            $("#custom-modal").appendTo("body");
        });
    }

    closeModal () {

        this.setState({open: false});
    }

    componentDidMount(){
        $(function(){
            $("#custom-modal").appendTo("body");
        });
    }

    render () {

        return (
            <div>
                <button onClick={this.openModal}>My modal</button>
                <Modal id="custom-modal" isOpen={this.state.open} onRequestClose={this.closeModal}>

                     // Modal body content here

                    <button onClick={this.closeModal}>Close</button>
                </Modal>
            </div>
        );
    }
}

And then using it like this:

import CustomModal from '../components/CustomModal'
...
<li><CustomModal/></li>

Hope this is of any help.

Upvotes: 1

Related Questions