5

I am using Grommet and am trying to get Layer (pretty much a modal) to work when a button is pressed. I know that my onClick works because I tried a simple console.log and it works. MyModal is also able to be displayed if I use ReactDOM and render it. I think my problem has something to do with how I am calling it or returning it? I want the modal to display when the button is clicked.

MyModal.js

import React, { Component } from 'react';
import Layer from 'grommet/components/Layer';
import Header  from 'grommet/components/Header';
import Heading from 'grommet/components/Heading';
import Section from 'grommet/components/Section';
import Paragraph from 'grommet/components/Paragraph';

export default class MyModal extends Component {  
  render () {
    return (
        <Layer closer={true} align="top">
            <Header>
                <Heading tag="h2">
                    Title
                </Heading>
            </Header>
            <Section>
                <Paragraph>
                    This is a simple dialog.
                </Paragraph>
            </Section>
        </Layer>
    );
  }
};

Main.js

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import App from 'grommet/components/App';
import Button from 'grommet/components/Button';
import MyModal from './components/MyModal';

export default class Main extends Component {
  getComponent(event) {
    return <MyModal/>;
  }
  render () {
    return (
      <App centered={false}>
           <Button onClick={this.getComponent.bind(this)} label="Action" />
      </App>
    );
  }
};
user3034572
  • 95
  • 1
  • 3
  • 9

1 Answers1

5

THE ISSUE:
You are trying to render your Modal into an in-line onClick handler.

SUGGESTED SOLUTION:

  • set a value in state to handle when the modal is shown

  • set the onClick to toggle this value

  • use this state to call another method in render to conditionally render the Modal

What your code could be amended to:

export default class Main extends Component {
  constructor(props) {
    super(props);
    this.state = {
        showModal: false  // set a value in state to store whether or
                          // not to show the Modal
    };

    // I've just put these binding in the constructor 
    // so as not to clock up the render method and they only
    // get called once during the lifetime of the component
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick(event) {  // switch the value of the showModal state
    this.setState({
      showModal: !this.state.showModal
    });
  }
  getComponent() {
    if (this.state.showModal) {  // show the modal if state showModal is true
      return <MyModal/>;
    } else {
      return null;
    }
  }
  render() {
    return (
      <App centered={false}>
        <Button onClick={this.handleClick} label="Action"/>
{this.getComponent} // call the method to render the modal here. </App> ); } };
/
Pineda
  • 7,435
  • 3
  • 30
  • 45
  • 1
    Yes this should work. Could you avoid binding `getComponent` as its execution is always bound to class closure? – yadhu Nov 26 '16 at 00:10
  • Functions are bound _when_ they are invoked and _not_ defined. However, in this case its binding is unnecessary since its scope isn't lost in an inline callback or a method that creates it's own context of `this`. I've amended my answer to include your suggestion because it's distracting otherwise. Thanks for the catch :) – Pineda Nov 26 '16 at 00:15
  • 1
    Thank you :+1: That was my whole point "it's distracting otherwise". I see many new React.js devs unnecessarily binding all of their class methods. We don't want to communicate a wrong idea. – yadhu Nov 26 '16 at 00:36