在一个组件中使用多种模态形式
Using multiple modal forms in one component
我有一个包含许多按钮的页面,我希望每个按钮在单击时打开自己的模态窗体。我有一个问题,多次使用相同的 form/modal 不会产生唯一的形式。例如,单击第一个按钮然后在表单中键入 "asdf" 也会填充由第二个按钮控制的表单。
我怎样才能重复使用我的 modals/forms 并仍然保持他们的数据不同?
我的代码:
import React from 'react';
import ReactDOM from 'react-dom';
import 'antd/dist/antd.css';
import './index.css';
import { Button, Modal, Form, Input, Radio } from 'antd';
const FormItem = Form.Item;
const CollectionCreateForm = Form.create()(
(props) => {
const { visible, onCancel, onCreate, form } = props;
const { getFieldDecorator } = form;
return (
<Modal
visible={visible}
title="Create a new collection"
okText="Create"
onCancel={onCancel}
onOk={onCreate}
>
<Form layout="vertical">
<FormItem label="Title">
{getFieldDecorator('title', {
rules: [{ required: true, message: 'Please input the title of collection!' }],
})(
<Input />
)}
</FormItem>
<FormItem label="Description">
{getFieldDecorator('description')(<Input type="textarea" />)}
</FormItem>
<FormItem className="collection-create-form_last-form-item">
{getFieldDecorator('modifier', {
initialValue: 'public',
})(
<Radio.Group>
<Radio value="public">Public</Radio>
<Radio value="private">Private</Radio>
</Radio.Group>
)}
</FormItem>
</Form>
</Modal>
);
}
);
class CollectionsPage extends React.Component {
state = {
visible: false,
};
showModal = () => {
this.setState({ visible: true });
}
handleCancel = () => {
this.setState({ visible: false });
}
handleCreate = () => {
const form = this.form;
form.validateFields((err, values) => {
if (err) {
return;
}
console.log('Received values of form: ', values);
form.resetFields();
this.setState({ visible: false });
});
}
saveFormRef = (form) => {
this.form = form;
}
render() {
return (
<div>
<Button type="primary" onClick={this.showModal}>New Collection</Button>
<CollectionCreateForm
ref={this.saveFormRef}
visible={this.state.visible}
onCancel={this.handleCancel}
onCreate={this.handleCreate}
/>
<Button type="primary" onClick={this.showModal}>New Collection</Button>
<CollectionCreateForm
ref={this.saveFormRef}
visible={this.state.visible}
onCancel={this.handleCancel}
onCreate={this.handleCreate}
/>
<Button type="primary" onClick={this.showModal}>New Collection</Button>
<CollectionCreateForm
ref={this.saveFormRef}
visible={this.state.visible}
onCancel={this.handleCancel}
onCreate={this.handleCreate}
/>
<Button type="primary" onClick={this.showModal}>New Collection</Button>
<CollectionCreateForm
ref={this.saveFormRef}
visible={this.state.visible}
onCancel={this.handleCancel}
onCreate={this.handleCreate}
/>
<Button type="primary" onClick={this.showModal}>New Collection</Button>
<CollectionCreateForm
ref={this.saveFormRef}
visible={this.state.visible}
onCancel={this.handleCancel}
onCreate={this.handleCreate}
/>
<Button type="primary" onClick={this.showModal}>New Collection</Button>
<CollectionCreateForm
ref={this.saveFormRef}
visible={this.state.visible}
onCancel={this.handleCancel}
onCreate={this.handleCreate}
/>
</div>
);
}
}
ReactDOM.render(<CollectionsPage />, document.getElementById('container'));
问题是每个形态被赋予相同的道具,所以被当成同一个形态来对待。在你的 render
函数中,你创建了多个 Button
s 和 CollectionCreateForm
s:
<Button type="primary" onClick={this.showModal}>New Collection</Button>
<CollectionCreateForm
ref={this.saveFormRef}
visible={this.state.visible}
onCancel={this.handleCancel}
onCreate={this.handleCreate}
/>
// repeated...
问题在于您将相同的道具传递给其中的每一个。您只设置了一个 ref
和一个 state
。每种形式都是完全相同的形式。当一个模态框可见时,它们都可见。
取而代之的是,您需要为每个表单保留单独的状态和引用。 (请继续阅读,不要只是复制此代码...这是错误的代码。)
class CollectionsPage extends React.Component {
state = {
visible1: false,
visible2: false
};
showModal1 = () => {
this.setState({ visible1: true });
}
showModal2 = () => {
this.setState({ visible2: true });
}
handleCancel1 = () => {
this.setState({ visible1: false });
}
handleCancel2 = () => {
this.setState({ visible2: false });
}
handleCreate1 = () => {
// ...
this.setState({ visible1: false });
}
handleCreate2 = () => {
// ...
this.setState({ visible2: false });
}
saveFormRef1 = (form) => {
this.form1 = form;
}
saveFormRef2 = (form) => {
this.form2 = form;
}
render() {
return (
<div>
<Button type="primary" onClick={this.showModal}>New Collection</Button>
<CollectionCreateForm
ref={this.saveFormRef1}
visible={this.state.visible1}
onCancel={this.handleCancel1}
onCreate={this.handleCreate1}
/>
<Button type="primary" onClick={this.showModal}>New Collection</Button>
<CollectionCreateForm
ref={this.saveFormRef2}
visible={this.state.visible2}
onCancel={this.handleCancel2}
onCreate={this.handleCreate2}
/>
</div>
);
}
}
我向您展示它是为了演示如何解决您的问题,但这是一种糟糕的实施方式。随着您添加更多的表单和模态,这将逐渐失控。我们可以通过将逻辑委托给子组件来改进。
首先,我们可以创建一个通用的 ModalToggle
将按钮和 form/modal 封装在一个中:
const CollectionsPage = () => (
<div>
<ModalToggle
label="New Collection"
modal={ CollectionFormModal }
/>
<ModalToggle
label="New Collection"
modal={ CollectionFormModal }
/>
</div>
);
我们可以通过将所有状态移动到内部来随意重用 ModalToggle
,这样它就可以自给自足了:
class ModalToggle extends React.Component {
state = {
visible: false
};
toggleModal = () => {
this.setState(prevState => ({ visible: !prevState.visible }));
}
render() {
const Modal = this.props.modal;
return (
<div>
<Button type="primary" onClick={this.toggleModal}>{this.props.label}</Button>
<Modal
visible={this.state.visible}
toggleVisibility={this.toggleModal}
/>
</div>
);
}
}
然后,我们只需要添加一个CollectionFormModal
来处理之前在CollectionsPage
中的其他逻辑:
class CollectionFormModal extends React.Component {
handleCancel = () => {
this.props.toggleVisibility();
}
handleCreate = () => {
// ...
this.props.toggleVisibility();
}
render() {
return (
<CollectionCreateForm
onCancel={this.handleCancel}
onCreate={this.handleCreate}
visible={this.props.visible}
/>
);
}
}
您可以进一步改进这一点,方法是将 CollectionCreateForm
的 Modal
部分向上移动到 CollectionFormModal
,而不是使用 ref
,将您的表单写成controlled component
我有一个包含许多按钮的页面,我希望每个按钮在单击时打开自己的模态窗体。我有一个问题,多次使用相同的 form/modal 不会产生唯一的形式。例如,单击第一个按钮然后在表单中键入 "asdf" 也会填充由第二个按钮控制的表单。
我怎样才能重复使用我的 modals/forms 并仍然保持他们的数据不同?
我的代码:
import React from 'react';
import ReactDOM from 'react-dom';
import 'antd/dist/antd.css';
import './index.css';
import { Button, Modal, Form, Input, Radio } from 'antd';
const FormItem = Form.Item;
const CollectionCreateForm = Form.create()(
(props) => {
const { visible, onCancel, onCreate, form } = props;
const { getFieldDecorator } = form;
return (
<Modal
visible={visible}
title="Create a new collection"
okText="Create"
onCancel={onCancel}
onOk={onCreate}
>
<Form layout="vertical">
<FormItem label="Title">
{getFieldDecorator('title', {
rules: [{ required: true, message: 'Please input the title of collection!' }],
})(
<Input />
)}
</FormItem>
<FormItem label="Description">
{getFieldDecorator('description')(<Input type="textarea" />)}
</FormItem>
<FormItem className="collection-create-form_last-form-item">
{getFieldDecorator('modifier', {
initialValue: 'public',
})(
<Radio.Group>
<Radio value="public">Public</Radio>
<Radio value="private">Private</Radio>
</Radio.Group>
)}
</FormItem>
</Form>
</Modal>
);
}
);
class CollectionsPage extends React.Component {
state = {
visible: false,
};
showModal = () => {
this.setState({ visible: true });
}
handleCancel = () => {
this.setState({ visible: false });
}
handleCreate = () => {
const form = this.form;
form.validateFields((err, values) => {
if (err) {
return;
}
console.log('Received values of form: ', values);
form.resetFields();
this.setState({ visible: false });
});
}
saveFormRef = (form) => {
this.form = form;
}
render() {
return (
<div>
<Button type="primary" onClick={this.showModal}>New Collection</Button>
<CollectionCreateForm
ref={this.saveFormRef}
visible={this.state.visible}
onCancel={this.handleCancel}
onCreate={this.handleCreate}
/>
<Button type="primary" onClick={this.showModal}>New Collection</Button>
<CollectionCreateForm
ref={this.saveFormRef}
visible={this.state.visible}
onCancel={this.handleCancel}
onCreate={this.handleCreate}
/>
<Button type="primary" onClick={this.showModal}>New Collection</Button>
<CollectionCreateForm
ref={this.saveFormRef}
visible={this.state.visible}
onCancel={this.handleCancel}
onCreate={this.handleCreate}
/>
<Button type="primary" onClick={this.showModal}>New Collection</Button>
<CollectionCreateForm
ref={this.saveFormRef}
visible={this.state.visible}
onCancel={this.handleCancel}
onCreate={this.handleCreate}
/>
<Button type="primary" onClick={this.showModal}>New Collection</Button>
<CollectionCreateForm
ref={this.saveFormRef}
visible={this.state.visible}
onCancel={this.handleCancel}
onCreate={this.handleCreate}
/>
<Button type="primary" onClick={this.showModal}>New Collection</Button>
<CollectionCreateForm
ref={this.saveFormRef}
visible={this.state.visible}
onCancel={this.handleCancel}
onCreate={this.handleCreate}
/>
</div>
);
}
}
ReactDOM.render(<CollectionsPage />, document.getElementById('container'));
问题是每个形态被赋予相同的道具,所以被当成同一个形态来对待。在你的 render
函数中,你创建了多个 Button
s 和 CollectionCreateForm
s:
<Button type="primary" onClick={this.showModal}>New Collection</Button>
<CollectionCreateForm
ref={this.saveFormRef}
visible={this.state.visible}
onCancel={this.handleCancel}
onCreate={this.handleCreate}
/>
// repeated...
问题在于您将相同的道具传递给其中的每一个。您只设置了一个 ref
和一个 state
。每种形式都是完全相同的形式。当一个模态框可见时,它们都可见。
取而代之的是,您需要为每个表单保留单独的状态和引用。 (请继续阅读,不要只是复制此代码...这是错误的代码。)
class CollectionsPage extends React.Component {
state = {
visible1: false,
visible2: false
};
showModal1 = () => {
this.setState({ visible1: true });
}
showModal2 = () => {
this.setState({ visible2: true });
}
handleCancel1 = () => {
this.setState({ visible1: false });
}
handleCancel2 = () => {
this.setState({ visible2: false });
}
handleCreate1 = () => {
// ...
this.setState({ visible1: false });
}
handleCreate2 = () => {
// ...
this.setState({ visible2: false });
}
saveFormRef1 = (form) => {
this.form1 = form;
}
saveFormRef2 = (form) => {
this.form2 = form;
}
render() {
return (
<div>
<Button type="primary" onClick={this.showModal}>New Collection</Button>
<CollectionCreateForm
ref={this.saveFormRef1}
visible={this.state.visible1}
onCancel={this.handleCancel1}
onCreate={this.handleCreate1}
/>
<Button type="primary" onClick={this.showModal}>New Collection</Button>
<CollectionCreateForm
ref={this.saveFormRef2}
visible={this.state.visible2}
onCancel={this.handleCancel2}
onCreate={this.handleCreate2}
/>
</div>
);
}
}
我向您展示它是为了演示如何解决您的问题,但这是一种糟糕的实施方式。随着您添加更多的表单和模态,这将逐渐失控。我们可以通过将逻辑委托给子组件来改进。
首先,我们可以创建一个通用的 ModalToggle
将按钮和 form/modal 封装在一个中:
const CollectionsPage = () => (
<div>
<ModalToggle
label="New Collection"
modal={ CollectionFormModal }
/>
<ModalToggle
label="New Collection"
modal={ CollectionFormModal }
/>
</div>
);
我们可以通过将所有状态移动到内部来随意重用 ModalToggle
,这样它就可以自给自足了:
class ModalToggle extends React.Component {
state = {
visible: false
};
toggleModal = () => {
this.setState(prevState => ({ visible: !prevState.visible }));
}
render() {
const Modal = this.props.modal;
return (
<div>
<Button type="primary" onClick={this.toggleModal}>{this.props.label}</Button>
<Modal
visible={this.state.visible}
toggleVisibility={this.toggleModal}
/>
</div>
);
}
}
然后,我们只需要添加一个CollectionFormModal
来处理之前在CollectionsPage
中的其他逻辑:
class CollectionFormModal extends React.Component {
handleCancel = () => {
this.props.toggleVisibility();
}
handleCreate = () => {
// ...
this.props.toggleVisibility();
}
render() {
return (
<CollectionCreateForm
onCancel={this.handleCancel}
onCreate={this.handleCreate}
visible={this.props.visible}
/>
);
}
}
您可以进一步改进这一点,方法是将 CollectionCreateForm
的 Modal
部分向上移动到 CollectionFormModal
,而不是使用 ref
,将您的表单写成controlled component