Close React Modal

蓝咒 提交于 2019-12-11 18:31:06

问题


I'm having a lot of problems trying to figure out how to add a functioning close button to my modal - constructor/props hasn't been working and I'm not sure what to put after onClick= in the button element.

class Modal extends React.Component {

// whenever component gets rendered to the screen we create a new div assigned to this.modalTarget
	componentDidMount() {
		this.modalTarget = document.createElement('div');
		// add class name to modal target
		this.modalTarget.className = 'modal';
		// take the div we just created and append it to the body tag in doc
		document.body.appendChild(this.modalTarget);
		// call method _render
		this._render();
	}

// whenever the component's about to update we do another render
// this render makes sure that if we get a new set of components or children in the modal
// we're going to render those to the parent div as well
	componentWillUpdate() {
		this._render();
	}

// clean up - whenever the component is about to unmount from the screen
// cleans up dom when the modal is removed from the component heirarchy
	componentWillUnmount() {
		// unmounts this.props.children
		ReactDOM.unmountComponentAtNode(this.modalTarget);
		document.body.removeChild(this.modalTarget);
	}

	_render() {
		// take react dom library and render a div that contains this.props.children
		// and render it into this.modalTarget
		ReactDOM.render(
			<Provider store= {store}>
				<Router>
					<div className="modal">
						{this.props.children}
						<button>Close</button>
					</div>
				</Router>
			</Provider>,
			this.modalTarget

回答1:


Several issues here. First, move away from directly manipulating the DOM. React uses a virtual DOM, so you don't need to manually add or remove DOM elements. React automatically handles this DOM manipulation through the render method. Also, you'll need to control this Modal utilizing some sort of state (isOpen). It be can through React's local state or through Redux's state. Either way, it needs to be controlled and compared against. Put simply, if it's open, render the Modal, if it's closed, render null.

In addition, this Modal component can be structured to be reusable. Simply add it as a child to another stateful parent component and include whatever children you want to render inside of it.

Working example:


components/Example.js (parent component)

import React, { Component } from "react";
import Modal from "../Modal";
import "./styles.css";

class Example extends Component {
  state = { isOpen: false };

  handleOpenModal = () => {
    this.setState({ isOpen: true });
  };

  handleCloseModal = () => {
    this.setState({ isOpen: false });
  };

  render = () => (
    <div className="example">
      <h2>Simple Modal Example</h2>
      <button
        className="uk-button uk-button-primary uk-button-small"
        onClick={this.handleOpenModal}
      >
        Open Modal
      </button>
      <Modal isOpen={this.state.isOpen} onCloseModal={this.handleCloseModal}>
        <h1 className="title">Hello!</h1>
        <p className="subtitle">There are two ways to close this modal</p>
        <ul>
          <li>Click outside of this modal in the grey overlay area.</li>
          <li>Click the close button below.</li>
        </ul>
        <button
          className="uk-button uk-button-danger uk-button-small"
          onClick={this.handleCloseModal}
        >
          Close
        </button>
      </Modal>
    </div>
  );
}

export default Example;

components/Modal.js (child component -- this has a lot of smaller components that were separated for reusability and ease of understanding -- they're basically simple divs with some styles attached -- see notes below)

import React from "react";
import PropTypes from "prop-types";
import BackgroundOverlay from "../BackgroundOverlay"; // grey background
import ClickHandler from "../ClickHandler"; // handles clicks outside of the modal
import Container from "../Container"; // contains the modal and background
import Content from "../Content"; // renders the "children" placed inside of <Modal>...</Modal>
import ModalContainer from "../ModalContainer"; // places the modal in the center of the page

// this is a ternary operator (shorthand for "if/else" -- if cond ? then : else)
// below can be read like: if isOpen is true, then return/render the modal, else return null
const Modal = ({ children, isOpen, onCloseModal }) =>
  isOpen ? (
    <Container>
      <BackgroundOverlay />
      <ModalContainer>
        <ClickHandler isOpen={isOpen} closeModal={onCloseModal}>
          <Content>{children}</Content>
        </ClickHandler>
      </ModalContainer>
    </Container>
  ) : null;

// these proptype declarations are to ensure that passed down props are 
// consistent and are defined as expected
Modal.propTypes = {
  children: PropTypes.node.isRequired, // children must be a React node
  isOpen: PropTypes.bool.isRequired, // isOpen must be a boolean
  onCloseModal: PropTypes.func.isRequired // onCloseModal must be a function
};

export default Modal;



回答2:


It looks like your modal is open based simply on whether it's rendered by the parent. Short of all together re-architecting this pattern, the only way to achieve what you want would be to pass in some kind of onClose callback:

class Parent extends React.Component {
  state = { isModalOpen: false };

  render() {
    return (<div>
      // Stuff
      {this.state.isModalOpen &&
        <Modal onClose={() => this.setState({ isModalOpen: false })}/>
      }
      // Stuff
    </div>);
  }
}

In your Modal:

<div className="modal">
    {this.props.children}
    <button onClick={this.props.onClose}>Close</button>
</div>


来源:https://stackoverflow.com/questions/55836921/close-react-modal

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!