问题
当使用对话框提交修改表单时,需要在输入框 Input 显示需要修改的数据,但使用 value 绑定对应数据,并未生效,具体代码如下:
function YwkclbEdit (props) {
....
const editData = props.data;
....
}
<Form.Item
name='hzxm'
label='患者姓名'
>
<Input placeholder="请输入患者姓名"
value={editData.name} />
</Form.Item>
结果,在控制台输出数据时,可以发现 editData 是有对应数据的,但对话框却没有显示对应数据。
测试一
如果不是 Input 组件和数据的问题,那么应该是嵌套了 Form 表单引起的。
因此,单独测试下,将 Input 单独提取出表单外。
<Input placeholder="请输入患者ID" value={editData.name} />
<Form
ref={ywkcEditForm}
name='ywkcEditForm'
size="small"
{...layout}
>
<Row justify="start" className="ywgllbAddFormItem">
<Col span="24" key="a1">
<Form.Item
name='hzid'
label='患者ID'
>
<Input placeholder="请输入患者ID" value={editData.name} />
</Form.Item>
</Col>
</Row>
结果如下,的确是嵌套表单引起的。
重新回顾Form组件相关内容,发现:
被设置了 name 属性的 Form.Item 包装的控件,表单控件会自动添加 value(或 valuePropName 指定的其他属性) onChange(或 trigger 指定的其他属性),数据同步将被 Form 接管,这会导致以下结果:
1、你不再需要也不应该用 onChange 来做数据收集同步(你可以使用 Form 的 onValuesChange),但还是可以继续监听 onChange 事件。
2、你不能用控件的 value 或 defaultValue 等属性来设置表单域的值,默认值可以用 Form 里的 initialValues 来设置。注意 initialValues 不能被 setState 动态更新,你需要用 setFieldsValue 来更新。
3、你不应该用 setState,可以使用 form.setFieldsValue 来动态改变表单值。
测试二
从文档解释可以发现错误在于数据同步被Form接管,因此,要将需要同步的数据交给Form使用(ps.虽然有除去name属性的方法,但先且按文档说明使用):
function YwkclbEdit (props) {
const ywkcEditForm = React.createRef();
const editData = props.data;
ywkcEditForm.current.setFieldsValue({ // 错误处
hzid: editData.name
})
...
<Form
ref={ywkcEditForm}
name='ywkcEditForm'
size="small"
{...layout}
>
<Row justify="start" className="ywgllbAddFormItem">
<Col span="24" key="a1">
<Form.Item
name='hzid'
label='患者ID'
>
<Input placeholder="请输入患者ID"/>
</Form.Item>
</Col>
</Row>
...
}
想法很美好,现实很骨感,直接出现错误:
TypeError: Cannot read property ‘setFieldsValue’ of null
没有对应属性,容易发现是表单创建失败。
继续查看文档,由于我们使用的函数组件,对应表单数据交互应该使用
Form.useform
测试三
根据文档提示,合理使用,成功实现数据交互。
function YwkclbEdit (props) {
const [ ywkcEditForm ] = Form.useForm(); // useForm() 返回的是表单数组,因此需要[]
const editData = props.data;
ywkcEditForm.setFieldsValue({
hzid : editData.name,
})
...
<Form
form={ywkcEditForm} // 修改处
name='ywkcEditForm'
size="small"
{...layout}
>
<Row justify="start" className="ywgllbAddFormItem">
<Col span="24" key="a1">
<Form.Item
name='hzid'
label='患者ID'
>
<Input placeholder="请输入患者ID"/>
</Form.Item>
</Col>
</Row>
...
}
演示效果如下,但是却出现了
Warning: Instance created by
useForm
is not connected to any Form element. Forget to passform
prop?
Uncaught SyntaxError: Unexpected token ‘<’
测试四
详细查看文档小字部分,发现在 Modal 中调用 Form 时,因为Modal还初始化,导致 Form 实例没有绑定表单,根据文档给 Modal 添加forceRender 属性,可以解决该警告。
在为Modal添加了 forecRender 属性后,选择任意数据后,会发现如下警告:
Warning: Cannot update during an existing state transition (such as within
render
). Render methods should be a pure function of props and state.
报错是由于引用的子组件通过props进行传递,传递的过程中 Modal 实际上已经处于render阶段了 ,render 还没结束时将数据传入会触发state 改变,在这个阶段如果你再改变这个state值的话就会报这个错。因此,不要在render的时候改变state就可以解决问题。
考虑到父组件传入的数据为只读,又需要通过异步操作避免render时本地state变动的问题,要避免直接传入父组件数据来为本地state赋值,同时,考虑到多用户情况,列表数据可能已经被修改,应该采用axios请求服务器发送对应ID的数据,保证数据实时性,代码如下:
// 子组件通过获取父组件传入的editId,向服务器申请对应数据并赋值
const searchById = (id) => {
console.log(id);
Conn.getYwkcById(id)
.then(res => {
ywkcEditForm.setFieldsValue({hzid: res.hzid, ywmc: res.ywmc,ywpp: res.ywpp, ywsl: res.ywsl})
})
.catch((err) => {
console.log(err);
})
};
searchById(props.editId);
结果很成功,先前出现的警告消失了,而且数据也能顺利交互。
总结
测试到此告一段落了,关于React、antd如何将嵌套表单的对话框组件化、实现数据交互作出了实践测试。
另外,Antd的说明文档非常重要的,遇到问题往往可以先查看说明文档,只要找到了对应的错误,往往会有成熟的解决方案。
引用
https://www.cnblogs.com/banyouxia/p/13188698.html