antd Modal里面使用Form 出现 Warning: Instance created by useForm is not connected to any Form element 警告的问题原因以及解决方案
现象
Modal里面使用Form页面加载出现警告:
原始代码
import React, { FC, useState, useEffect } from 'react'
import { Modal, Form } from 'antd'
import axios from '@/api/config'
import { ModifyModalProps } from '../../interface'
import { URL } from '../../constant'
const formItemLayout = {
labelCol: {
span: 6,
},
wrapperCol: {
span: 14,
},
}
const ModifyModal: FC<ModifyModalProps> = ({ modifyModalData, setModifyModal }) => {
const { visible, id } = modifyModalData
const [form] = Form.useForm()
const [loading, setLoading] = useState<boolean>(false)
useEffect(() => {
if (!orgId) {
form.resetFields()
return
}
setLoading(true)
// 获取form的initialValues
axios
.get(URL, { params: { id } })
.then((res: any) => {
setLoading(false)
if (res?.data) {
form.setFieldsValue({
...res.data,
})
}
})
.catch(() => {
setLoading(false)
})
}, [orgId])
const handleSubmit = async () => {
try {
setLoading(true)
const values = await form.validateFields()
console.log(values)
setLoading(false)
} catch (e) {
setLoading(false)
}
}
return (
<Modal
visible={visible}
title='标题'
destroyOnClose
onCancel={() => {
setModifyModal({ visible: false })
}}
onOk={handleSubmit}
confirmLoading={loading}
>
<Form
labelWrap
form={form}
{...formItemLayout}
colon={false}
name='pay-modify-form'
>
// some FormItem
// ...
</Form>
</Modal>
)
}
export default ModifyModal
问题原因
ant design在Modal中使用Form表单,并且通过Form.useForm(), 获取form对象将其挂载到指定的Form表单后出现Instance created by useForm is not connect to any Form element. Forget to pass form prop警告。
大部分人可能以为:这是由于ant design的Modal组件会在Form表单之前创建,因此当页面初始化时form对象会找不到可关联的Form表单,于是出现上述警告。
但其实不是,出现这个警告的根本原因是form组件还没有渲染,就调用了 form 的方法(给表单赋值、获取表单的值等等)。百度这个警告内容给出的一堆方法是给什么 Model 加什么属性(如下方法1),都没有真正说到导致这个问题的原因,可能所处具体情景不一样吧,希望各位看官对症下药!
解决方法
- 网上普遍的方法是将 Modal组件中添加上
getContainer={false}属性
我试了一下并不起作用,而且如果当前Dom节点是antd的table的话,加载td,tr的样式还会影响到Modal样式。所以次方法不建议使用。
- modal加载后 form挂载之后再调用from的方法 上述代码改造如下:
import React, { FC, useState, useEffect } from 'react'
import { Modal, Form } from 'antd'
import axios from '@/api/config'
import { ModifyModalProps } from '../../interface'
import { URL } from '../../constant'
const formItemLayout = {
labelCol: {
span: 6,
},
wrapperCol: {
span: 14,
},
}
const ModifyModal: FC<ModifyModalProps> = ({ modifyModalData, setModifyModal }) => {
const { visible, id } = modifyModalData
const [form] = Form.useForm()
const [loading, setLoading] = useState<boolean>(false)
useEffect(() => {
/*----------------start-------------------
等到真正去挂载form后再调用form的方法
*/
if (!visible) {
return
}
/*----------------end-----------------*/
if (!orgId) {
form.resetFields()
return
}
setLoading(true)
axios
.get(URL, { params: { id } })
.then((res: any) => {
setLoading(false)
if (res?.data) {
form.setFieldsValue({
...res.data,
})
}
})
.catch(() => {
setLoading(false)
})
}, [orgId, visible])
const handleSubmit = async () => {
try {
setLoading(true)
const values = await form.validateFields()
console.log(values)
setLoading(false)
} catch (e) {
setLoading(false)
}
}
return (
<Modal
visible={visible}
title='标题'
destroyOnClose
onCancel={() => {
setModifyModal({ visible: false })
}}
onOk={handleSubmit}
confirmLoading={loading}
>
<Form
labelWrap
form={form}
{...formItemLayout}
colon={false}
name='pay-modify-form'
>
// some FormItem
// ...
</Form>
</Modal>
)
}
export default ModifyModal
或者在调用Modal组件的时候等到需要挂载时再挂载,:
{modifyModalData.visible&&<ModifyModal modifyModalData={modifyModalData} setModifyModal={setModifyModal}/>
这两种改造方案都能解决问题!