Я не уверен, зачем вам нужно создавать родительский компонент Modal
, когда вы можете сделать Modal
простым повторно используемым child
компонентом.
См. здесь для подробного объяснения того, как получить родительский элемент, который контролирует дочерний модал.
Однако, если у вас ДОЛЖЕН быть родительский компонент Modal
, вы можете создать render prop
для передачи props
для использования его children
.
Рабочий пример :
![Edit Parent Modal](https://codesandbox.io/static/img/play-codesandbox.svg)
компоненты / Modal.js (parent
компонент - здесь есть множество более мелких компонентов, которые были разделены для повторного использования и простоты понимания - они в основном простые div
с некоторыми styles
прилагается - см. Примечания ниже)
import React, { Fragment, Component } 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
class Modal extends Component {
state = { isOpen: false };
handleOpenModal = () => {
this.setState({ isOpen: true });
};
handleCloseModal = () => {
this.setState({ isOpen: false });
};
// this is a ternary operator (shorthand for "if/else" -- if cond ? then : else)
// below can be read like: if isOpen is true, then render the modal,
// else render whatever the child component is returning (in this case,
// initially returning an "Open Modal" button)
render = () =>
this.state.isOpen ? (
<Container>
<BackgroundOverlay />
<ModalContainer>
<ClickHandler
isOpen={this.state.isOpen}
closeModal={this.handleCloseModal}
>
<Content>
{this.props.children({
isOpen: this.state.isOpen,
onCloseModal: this.handleCloseModal,
onOpenModal: this.handleOpenModal
})}
</Content>
</ClickHandler>
</ModalContainer>
</Container>
) : (
<Fragment>
{this.props.children({
isOpen: this.state.isOpen,
onCloseModal: this.handleCloseModal,
onOpenModal: this.handleOpenModal
})}
</Fragment>
);
}
// these proptype declarations are to ensure that passed down props are
// consistent and are defined as expected
Modal.propTypes = {
children: PropTypes.func.isRequired // children must be a function
};
export default Modal;
компоненты / Example.js (child
компонент принимает isOpen
, onCloseModal
и onOpenModal
от parent
- при таком подходе, как вы заметите, есть дубликаты isOpen
логика. Хотя этот подход дает вам полный контроль над родителем, он повторяется. Однако вы можете упростить свои компоненты, переместив логику кнопки «Открыть модальные» в родительский объект и передав опору типа <Modal btnTitle="Open Modal">
, чтобы сделать это несколько гибко, НО вы все равно потеряете контроль над тем, что изначально отображается, когда isOpen
равно false
.)
import React, { Fragment } from "react";
import Modal from "../Modal";
import "./styles.css";
const Example = () => (
<div className="example">
<h2>Parent Modal Example</h2>
<Modal>
{({ isOpen, onCloseModal, onOpenModal }) =>
isOpen ? (
<Fragment>
<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={onCloseModal}
>
Close
</button>
</Fragment>
) : (
<button
className="uk-button uk-button-primary uk-button-small"
onClick={onOpenModal}
>
Open Modal
</button>
)
}
</Modal>
</div>
);
export default Example;