[英]React ES6 component modal API
I would like to create component API for dialog window, based on https://github.com/reactjs/react-modal 我想基于https://github.com/reactjs/react-modal为对话框窗口创建组件API
I want render react component with renderDOM, get component instance and call API of modal, it does mean for example open(), close() etc. 我想用renderDOM渲染render组件,获取组件实例并调用模态的API,这的确意味着例如open(),close()等。
So, more precisely I would like to work with current state of component, (like API works) not with props. 因此,更准确地说,我想使用组件的当前状态(例如API工作)而不使用道具。
I have simple base class for all modals: 我对所有模态都有简单的基类:
export class BaseModal extends Modal {
constructor() {
super();
this.state = BaseModal._getInitState();
}
static get style() {
return {
content: {
top: '50%',
left: '50%',
right: 'auto',
bottom: 'auto',
marginRight: '-50%',
transform: 'translate(-50%, -50%)'
}
};
}
open() {
this.setState({isOpen: true});
}
close() {
this.setState({isOpen: false});
}
render() {
return this.state.isOpen ? (
<div className="modal modal__{this.name}">
<Modal isOpen={this.state.isOpen}
onRequestClose={this.close}
style={BaseModal.style}
contentLabel={this.getHeaderContent()}
parentSelector={BaseModal._getParentSelector}>
<button onClick={this.close}>X</button>
<div className="modal__body">
{this.getBodyContent()}
</div>
<div className="modal__footer">
{this.getFooterContent()}
</div>
</Modal>
</div>
) : null;
}
getHeaderContent() {
throw new Error("Not implement in child class.");
}
getBodyContent() {
throw new Error("Not implement in child class.");
}
getFooterContent() {
throw new Error("Not implement in child class.");
}
static _getInitState() {
let state = {};
state.isOpen = false;
}
}
Now I have child component: 现在我有子组件:
export class RecommendTripModal extends BaseModal {
getHeaderContent() {
return "Test modal dialog";
}
getBodyContent() {
return <p>Test modal body</p>;
}
getFooterContent() {
return <p>Test modal footer</p>;
}
}
Ok, this is fine, but now I want to call something like this: 好的,这很好,但是现在我想调用这样的名称:
let recommendedTripModal = ReactDOM.render(React.createElement(RecommendTripModal, null), document.querySelector("#modals"));
//open dialog
recommendedTripModal.open();
But now is problem with context. 但是现在是上下文问题。 Because
this.state.isOpen
has RecommendTripModal context and state is null. 因为
this.state.isOpen
具有RecommendTripModal上下文,所以状态为null。 Is there way, how to solved this problem with react? 有没有办法,如何用反应来解决这个问题? And is this solid way?
这是可靠的方法吗? Or I should create required API different way?
还是我应该以其他方式创建所需的API?
Thank you for your time! 感谢您的时间!
Okay, let's dig a little bit deeper here, best way is to use React context and HoC magic power 好的,让我们在这里进行更深入的探讨,最好的方法是使用React上下文和HoC魔术功能
Modal.js Modal.js
import React from "react";
import PropTypes from "prop-types";
import { omit } from "lodash";
export class Modal extends React.Component {
static contextTypes = {
modalOpen: PropTypes.bool
};
static propTypes = {
children: PropTypes.node
};
render() {
if (!this.context.modalOpen) return null;
return (
<div>
<h1>I am base modal title</h1>
<div>{this.props.children}</div>
</div>
);
}
}
export class ModalContext extends React.Component {
static childContextTypes = {
modalOpen: PropTypes.bool
};
static defaultProps = {
onOpen: () => {},
onClose: () => {}
};
static propTypes = {
children: PropTypes.func.isRequired
};
constructor(...args) {
super(...args);
this.handleOpen = this.handleOpen.bind(this);
this.handleClose = this.handleClose.bind(this);
}
state = {
isOpen: false
};
getChildContext() {
return {
modalOpen: this.state.isOpen
};
}
handleClose() {
if (this.state.isOpen) {
this.setState({ isOpen: false });
}
}
handleOpen() {
if (!this.state.isOpen) {
this.setState({ isOpen: true });
}
}
render() {
const { identity, children } = this.props;
return children({
[identity]: {
open: this.handleOpen,
close: this.handleClose,
isOpen: this.state.isOpen
}
});
}
}
export default function modal(initialModalProps = {}) {
return function(Component) {
const componentName =
Component.displayName || Component.name || "Component";
return class extends React.Component {
static displayName = `Modal(${componentName})`;
static propTypes = {
identity: PropTypes.string
};
static defaultProps = {
identity: "modal"
};
render() {
const { identity } = this.props;
return (
<ModalContext
identity={identity}
{...initialModalProps}
{...this.props[identity]}
>
{modalProps => (
<Component
{...omit(this.props, identity, "identity")}
{...modalProps}
/>
)}
</ModalContext>
);
}
};
};
}
HelloWorldModal.js HelloWorldModal.js
import React from "react";
import withModal, { Modal } from "./modal";
class HelloWorldModal extends React.Component {
render() {
const { modal } = this.props;
return (
<div>
<button type="button" onClick={modal.open}>
Open Modal
</button>
<button type="button" onClick={modal.close}>
Close Modal
</button>
<Modal>Yeah! I am sample modal!</Modal>
</div>
);
}
}
export default withModal()(HelloWorldModal);
In case you are lazy, I prepared a codesandbox with working code :) 如果你很懒,我准备了一个带有工作代码的codeandbox :)
https://codesandbox.io/s/2oxx2j4270?module=%2Fsrc%2FHelloWorldModal.js https://codesandbox.io/s/2oxx2j4270?module=%2Fsrc%2FHelloWorldModal.js
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.