Form编辑初始值问题

838 阅读2分钟

        antd版本:5.5.2,react版本:18.2.0

        在使用antd实现编辑modal的时候,发现每次回显都会延迟一步(这次回显的是上一次的值)。简化后代码如下:

import { Modal, Form, Input } from 'antd';const A = () => {    const [form] = Form.useForm(); return (<div>        ...        <Modal title='xxx' open={isModalOpen} destroyOnClose>            <Form form={form} preserve={false} initialValues={obj}>                <Form.Item label="xxx" name="aaa">                    <Input ></Input>                </Form.Item>            </Form>        </Modal>    </div>)}export default A;

        开始怀疑是modal的问题,加了destroyOnClose和preserve={false}也不好使。之后尝试过清除form表单值或者重置为空都不管用。也尝试过通过变量控制表单重新生成与销毁也不管用。之后怀疑过是modal重新打开时候初始值没有设置成功,也不是(因为第二次打开时候虽然显示的是第一次的值,但是我通过执行form.resetFields()是可以变成第二次传过来初始值的)。后来通过反复实验找出是Form.useForm本身的问题。下面列出几种解决办法:

        第一种:之前写在form里的initialValues改成写在Form.Item里的initialValue。原因可能是因为每次渲染Form.Item的时候都会通过cloneElement重新生成表单项,也导致这里的初始值能生效。想了解更详细的请看这里zhuanlan.zhihu.com/p/552048638

        第二种:不使用默认值,都通过form.setFieldsValue来设置值。(这个方法是万能的,几乎所有表单类问题都能解决)

        第三种(这个方法不推荐使用,只是了解):上边说过,第二次打开的时候通过form.resetFields()可以把值更新为最新值的。时机可以选在监听初始值obj改变以后。这里还有个坑,值改了如果直接form.resetFields也不生效,需要加个定时器(0s的也行)。

        其实我们观察发现,为什么form表单每次都是重新创建的,而再次打开还能记录到之前的值呢?原因就是我们使用了

const [form] = Form.useForm();
...
form={form}
...

表单的信息被存在了form里了,即使Form组件已经销毁了。所以我们只要保证不让它把Form(组件)信息存到form(变量)里或者每次打开都是一个新的form(变量)就不会有问题了。

        第四种:如果我们后续操作没有用到form.setFieldsValue等方法,就没必要写form={form}了,不写这个就不会有上边那个回显问题了。

       第五种:将Form部分单独写成一个组件,在这个组件里每次重新渲染都生成一个全新的form。简化代码如下:

import { Modal, Form, Input } from 'antd';const B = ({ obj }) => {    const [form] = Form.useForm();    return <Form form={form} initialValues={obj}>        <Form.Item label="xxx" name="aaa">            <Input ></Input>        </Form.Item>    </Form>}const A = () => {    return (<div>        <Modal title='xxx' open={isModalOpen} destroyOnClose>            <B obj={obj} />        </Modal>    </div>)}export default A;

        第六种:不使用Form.useForm,而是使用ref代替。其实也是相当于每次生成一个新的form。简化代码如下:

import { Modal, Form, Input } from 'antd';import { useState } from 'react';const A = () => {    const [form, setForm] = useState<any>()    const formRefCallback = (ref) => {        if (ref) setForm(ref)    }    return (<div>        <Modal title='xxx' open={isModalOpen} destroyOnClose>            <Form ref={formRefCallback} initialValues={obj}>                <Form.Item label="xxx" name="aaa">                    <Input ></Input>                </Form.Item>            </Form>        </Modal>    </div>)}export default A;

参考文章:juejin.cn/post/722557…