Joachim
Joachim

Reputation: 45

How do I make it so only a specific modal appears when I press a button in React?

Currently trying to make modals in React and want to make a grid where "button 1" shows "modal 1" and "button 2" shows "modal 2" etc. At the moment when I press my button to show a modal it shows both modal 1 and modal 2. How do I set it up so button 1 only opens modal 1?

This is my App.js:

import React from 'react';
import './main.css';
import Modal from './components/Modal/modal';

class App extends React.Component {
  state = {
    show: false
  };

  showModal = x => {
    this.setState({
      show: !this.state.show
    });
  };

  render() {
    return (
      <div>
        <div className="button-container">
          <button className="toggle-button" onClick={x => {
            this.showModal(x);
          }}>Show yourself Modal!</button>
        </div>
        <Modal onClose={this.showModal} show={this.state.show} title="Test modal 1" id="1">Lorem ipsum</Modal>
        <Modal onClose={this.showModal} show={this.state.show} title="Test modal 2" id="2">I am a different modal</Modal>
      </div>
    );
  }
}

export default App;

And this is my modal.js component:

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import './modal.css';

export default class Modal extends Component {
    onClose = x => {
        this.props.onClose && this.props.onClose(x);
    };

    render() {
        if(!this.props.show) {
            return null;
        }

        return (
            <div className="modal-wrapper">
                <h2 className="modal-header">{this.props.title}</h2>
                <div>{this.props.children}</div>
                <div>
                    <button className="modal-close" onClick={this.onClose}></button>
                </div>
            </div>
        )
    }
}

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

Upvotes: 1

Views: 898

Answers (3)

m.sohail
m.sohail

Reputation: 96

If you require Button for every Modal and control its behaviour with it then you can introduce a state to the modal component itself by doing something like this:

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import './modal.css';

export default class Modal extends Component {
    constructor(props) {
       super(props);
       this.state = {
         showModal: false,
       }
    }   

    toggleShow = () => {
        const { showModal } = this.state;
        this.setState({showModal: !showModal})
    };

    render() {
        const { showModal } = this.state;        
        return (
            <div className="modal-wrapper">
                { showModal &&
                <div>
                    <h2 className="modal-header">{this.props.title}</h2>
                    <div>{this.props.children}</div>
                </div>
                }
                <div>
                    <button className="modal-close" onClick={() => this.toggleShow()}>{this.props.btnText}</button>
                </div>
            </div>
        )
    }
}

It can be build further to alter the default behaviour. This should clean your App.js code.

Upvotes: 1

Brian Thompson
Brian Thompson

Reputation: 14385

The simplest way would be to add a second key to your state so that you have a way to manage showing both modals independently.

class App extends React.Component {
  state = {
    show1: false,
    show2: false
  };

Then make your change function to be a curried function that accepts a parameter to update the correct part of state. In order to use a variable to access an object key, we need to access it as an array like this:

  showModal = (modal) => (e) => {
    this.setState({
      [modal]: !this.state[modal]
    });
  };

Then use it like this:

  render() {
    return (
      <div>
        <div className="button-container">
          <button className="toggle-button" onClick={this.showModal('show1')}>Show yourself Modal 1!</button>
          <button className="toggle-button" onClick={this.showModal('show2')}>Show yourself Modal 2!</button>
        </div>
        <Modal onClose={this.showModal('show1')} show={this.state.show1} title="Test modal 1" id="1">Lorem ipsum</Modal>
        <Modal onClose={this.showModal('show2')} show={this.state.show2} title="Test modal 2" id="2">I am a different modal</Modal>
      </div>
    );
  }
}

Upvotes: 2

dougajmcdonald
dougajmcdonald

Reputation: 20057

At the moment you have nothing in your state to tell which modal to show. You're using this.state.show to control the visibility of both modals.

You could introduce a state property in your App component which is used to choose which modal to show. For example, passing in a modalId or similar to your click handler. (disclaimer: untested syntax, but the principal is right!)

So your state may look like this:

state = {
  [
    { 
      id: 1,
      show: false
    },
    { 
      id: 2,
      show: false
    },
  ]
}

Then, in your click handler, you'd need to pass in the id of the modal to show / hide. You'd need to determine this from something in your UI.

showModal(id) => {
  this.setState({
    [id]: !this.state[id].show
  })
}

Upvotes: 1

Related Questions