1

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.(…)
  • What is `Modal`? Presumably in your case it is `undefined` – zerkms Nov 06 '16 at 00:35
  • Modal is the `Modal` component provided by `React` and I've imported it in my file. –  Nov 06 '16 at 00:39
  • 2
    `import { Modal } from ...` Then read http://stackoverflow.com/q/31096597/251311 – zerkms Nov 06 '16 at 00:43
  • This is the error that I get, on deconstructing, `invariant.js:38 Uncaught Error: onlyChild must be passed a children with exactly one child.` –  Nov 06 '16 at 00:44
  • 1
    Show the corresponding code, we have no idea what you are currently running there. – zerkms Nov 06 '16 at 00:46

4 Answers4

1

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.

gustavaa
  • 41
  • 4
  • Could you explain what you're doing with the jquery function and inside componentDidMount. I'm pretty new to javascript and React. Also I'm not using jquery in my project. Can I now launch this using my handleClick function. –  Nov 06 '16 at 00:57
  • The jquery-funcitons is inserting the modal html-code to the body of the document when we open it. Is there a specfic reason as to why you are not using jquery in the project? Otherwise you can easily implement it by adding `` – gustavaa Nov 06 '16 at 01:19
  • In the head of your index html file that is. – gustavaa Nov 06 '16 at 01:19
0

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.

squall3d
  • 1,737
  • 14
  • 12
0

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/

fckt
  • 571
  • 4
  • 12
0

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

user12575927
  • 311
  • 3
  • 8