Antd 中Modal和Form配合时验证器无效和默认值不更新问题

Antd 中Modal和Form配合时验证器无效和默认值不更新问题

验证器无效问题

发现过程

在跟着B站React实战课程走的时候,因为课程是Antd V3我使用的是V4。所以在遇到Modal中嵌套From时,课程使用的是高阶组件的方式实现验证器。我看见V4直接有rules(包括使用validator)属性,直接设置后发现无效。

解决方法

其实在官方文档有Modal组件配合的实例。

import React, { useState } from 'react';
import { Button, Modal, Form, Input, Radio } from 'antd';

interface Values {
  title: string;
  description: string;
  modifier: string;
}

interface CollectionCreateFormProps {
  visible: boolean;
  onCreate: (values: Values) => void;
  onCancel: () => void;
}

const CollectionCreateForm: React.FC<CollectionCreateFormProps> = ({
  visible,
  onCreate,
  onCancel,
}) => {
  const [form] = Form.useForm();
  return (
    <Modal
      visible={visible}
      title="Create a new collection"
      okText="Create"
      cancelText="Cancel"
      onCancel={onCancel}
      onOk={() => {
        form
          .validateFields()
          .then(values => {
            form.resetFields();
            onCreate(values);
          })
          .catch(info => {
            console.log('Validate Failed:', info);
          });
      }}
    >
      <Form
        form={form}
        layout="vertical"
        name="form_in_modal"
        initialValues={{ modifier: 'public' }}
      >
        <Form.Item
          name="title"
          label="Title"
          rules={[{ required: true, message: 'Please input the title of collection!' }]}
        >
          <Input />
        </Form.Item>
        <Form.Item name="description" label="Description">
          <Input type="textarea" />
        </Form.Item>
        <Form.Item name="modifier" className="collection-create-form_last-form-item">
          <Radio.Group>
            <Radio value="public">Public</Radio>
            <Radio value="private">Private</Radio>
          </Radio.Group>
        </Form.Item>
      </Form>
    </Modal>
  );
};

const CollectionsPage = () => {
  const [visible, setVisible] = useState(false);

  const onCreate = values => {
    console.log('Received values of form: ', values);
    setVisible(false);
  };

  return (
    <div>
      <Button
        type="primary"
        onClick={() => {
          setVisible(true);
        }}
      >
        New Collection
      </Button>
      <CollectionCreateForm
        visible={visible}
        onCreate={onCreate}
        onCancel={() => {
          setVisible(false);
        }}
      />
    </div>
  );
};

ReactDOM.render(<CollectionsPage />, mountNode);
.collection-create-form_last-form-item {
  margin-bottom: 0;
}

CollectionCreateForm 时最关键的部分,这里使用里Reacthook语法。我通过一些更改把它还是变成了封装一个类(感觉这样也不好)。

代码如下:

import { Form, Modal } from 'antd';
import React, { Component } from 'react';
import { ICategory } from './DataModel';
import { ModalStatusCode } from './ModalStatusCode';

interface Values {
	title: string;
	description: string;
	modifier: string;
}

interface ModalFromProps {
	showStatus: ModalStatusCode;
	onCancel: () => void;
	category: ICategory;
	element: React.ReactNode;
	expectedStatus: ModalStatusCode;
	title: string;
}

interface ModalState {
	name: string;
}

class ModalForm extends Component<ModalFromProps, ModalState> {


	constructor(props: ModalFromProps) {
		super(props);
		this.state = {
			name: '',
		};
	}

	private onCancel = () => {
		this.props.onCancel();
	};


	private CreateModalFrom = (): any => {
    const [form] = Form.useForm();
		const { title } = this.props;
		return (
			<Modal
				visible={this.props.showStatus === this.props.expectedStatus}
				title={title}
				okText="Ok"
				cancelText="Cancel"
				onCancel={this.onCancel}
				onOk={() => {
					form
						.validateFields()
						.then((values) => {
							form.resetFields();
							console.log(values);
						})
						.catch((info) => {
							console.log('Validate Failed:', info);
						});
				}}
			>
				<Form form={form}>
					<Form.Item name="title" rules={[{ required: true, message: '请输入品类名称' }]} initialValue={this.props.category.name} >
						{this.props.element}
					</Form.Item>
				</Form>
			</Modal>
		);
	};

	render() {
		return <this.CreateModalFrom />;
	}
}

因为是React新手,所以还是凭着自己理解去封装。这样导致自定义ModalForm组件为了得到某些值必须经过某个中间组件去传,看起来就很难看且值没有任何更改,很难看。希望各位也能给个好建议。

调用ModalForm代码:

interface IUpdateFormProps {
	category: ICategory;
	onCancel: () => void;
	showStatus: ModalStatusCode;
}

interface IUpdateFormState {
}

export default class UpdateFrom extends Component<IUpdateFormProps, IUpdateFormState> {

  

	render() {

		return (
			<ModalForm {...this.props} element={<Input placeholder="请输入分类名称"></Input>} expectedStatus={ModalStatusCode.Update} title='更新分类'></ModalForm>
		);
	}
}

对应页面上有一个列表,列表有一个修改功能。点击之后Form的input框里面显示该行属性名称。但是奇怪的是这样写名称会不更新。始终是第一个点击那一行,尝试后发现点击OK按钮名称会更新。查看代码后发现是

form.resetFields();

起的作用,因此想着每次都调用这个方法,但尝试一番无果。晚上再去看Modal的官方文档后发现这么一句话。

<Modal /> 默认关闭后状态不会自动清空, 如果希望每次打开都是新内容,请设置 destroyOnClose。

<Modal /> 和 Form 一起配合使用时,设置 destroyOnClose 也不会在 Modal 关闭时销毁表单字段数据,
需要设置 <Form preserve={false} />。

于是想着能不能每次打开都是重新渲染,解决这个问题。于是在添加上面的属性后便解决了问题。

思考

虽然解决了问题但是感觉有更好解决方案或者另一种实现方法,如果能还希望不吝赐教。

随笔

从偶然的出生,到必然的死亡,我们都将经历孤独和徘徊。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
antdvue3,要使resetFields生效,需要在modal关闭调用resetFields方法。具体的代码实现如下: ``` <template> <div> <a-button @click="openModal">打开modal</a-button> <a-modal v-model:visible="visible" @ok="handleOk" @cancel="handleCancel"> <a-form ref="form" :model="form"> <a-form-item label="姓名" :rules="{ required: true, message: '请输入姓名' }"> <a-input v-model:value="form.name" /> </a-form-item> <a-form-item label="年龄" :rules="{ required: true, message: '请输入年龄' }"> <a-input-number v-model:value="form.age" /> </a-form-item> </a-form> </a-modal> </div> </template> <script> import { ref } from 'vue'; import { Button, Modal, Form, Input, InputNumber } from 'ant-design-vue'; export default { components: { 'a-button': Button, 'a-modal': Modal, 'a-form': Form, 'a-form-item': Form.Item, 'a-input': Input, 'a-input-number': InputNumber, }, setup() { const visible = ref(false); const form = ref({ name: '', age: null }); const openModal = () => { visible.value = true; }; const handleOk = () => { // 提交表单 form.value = { name: '', age: null }; visible.value = false; }; const handleCancel = () => { // 关闭modal调用resetFields方法 const formRef = this.$refs.form; formRef.resetFields(); form.value = { name: '', age: null }; visible.value = false; }; return { visible, form, openModal, handleOk, handleCancel, }; }, }; </script> ``` 在handleCancel方法,我们首先获取form的ref,然后调用resetFields方法重置表单数据,最后将form的值设置为空对象{},将visible的值设置为false,关闭modal。这样就能够使resetFields生效了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值