Antd-表单在Modal与Drawer中回显踩坑

因业务需要需要在Modal中实现表单的回显,最开始使用了如下方法

js 复制代码
const initialValues = useRef({});
....
useEffect(() => {
    if (!id) return;
    setLoading(true);
    getTreatMethod({ id })
      .then((res) => {
        initialValues.current = {
          ...res,
          inStatusDtos: res.hospitalizationStatusDtos.map((item) => {
            return item.id.toString();
          }),
        };
        setLoading(false);
      })
      .catch((e) => {
        message.error((e as Error).message);
        setLoading(false);
      });
  }, [id]);
  
  <Form
        initialValues={initialValues.current}
        name="basic"
        form={form}
        onFinish={onFinish}
        layout="vertical"
        className={styles.form}
        disabled={status === DrawerStatus.Check}
      >...
     </Form>

但是发现用initialValues来进行回显,表单的值始终为上一次表单的值。

在文档中发现如下说明

  • <Modal /> 默认关闭后状态不会自动清空,如果希望每次打开都是新内容,请设置 destroyOnClose。
  • <Modal /> 和 Form 一起配合使用时,设置 destroyOnClose 也不会在 Modal 关闭时销毁表单字段数据,需要设置 <Form preserve={false} />。

根据文档在Form和Modal中添加了对应的字段,却并没有解决问题。

于是开始从头又看了一遍代码,怀疑是不是因为在设置关闭Modal后表单并没有重新渲染。于是又添加了如下代码

js 复制代码
  useEffect(() => {
    form.resetFields();
  }, [open]);

发现仍未解决问题,突然想起来Form表单回显可以用setFieldsValue

将代码改为

js 复制代码
useEffect(() => {
    if (!id) return;
    setLoading(true);
    getTreatMethod({ id })
      .then((res) => {
        form.setFieldsValue({
          ...res,
          inStatusDtos: res.hospitalizationStatusDtos.map((item) => {
            return item.id.toString();
          }),
        });
        setLoading(false);
      })
      .catch((e) => {
        message.error((e as Error).message);
        setLoading(false);
      });
  }, [id]);

解决问题

在修改代码中间几个小时一直在思考究竟是为什么会出现这个错误,一直没有想到为什么,现在回过头去梳理的时候突然发现多半是因为antd表单initialValues初始化时机的问题。

Form在Modal打开时就进行了初始化,在执行getTreatMethod()拿到res给initialValues赋值时已经完成了表单初始化,而且因为是使用ref去记录并不会对组件进行重新渲染,也解释了为什么始终表单的值始终是上一个表单,而不是当前表单,出现了闭包陷阱。

回顾整个问题,发现起因是我对Ref的滥用以及掌握程度不深。在没有涉及到Modal和Drawer的表单都是用ref去储存initialValues并未发现此问题,总觉得使用ref就不会出现这种闭包问题。而且最关键的是所有回显都是用initialValues而忽略了form的方法setFieldsValue从而造成了这个bug。

总结

  • Antd表单回显有两个方法initialValues和form.setFieldsValue(),一个有问题就换另一个
  • 在涉及Modal与Drawer的表单回显直接用form.setFieldsValue()
  • 不要滥用ref,不要觉得只要用了ref就不会出现闭包陷阱
相关推荐
liangshanbo121517 分钟前
面试题:如何优化 Webpack 的打包速度?
前端·webpack·node.js
wengad25 分钟前
从 wangEditor 迁到 wangEditor-next
前端·javascript·vue.js
行者-全栈开发2 小时前
【前端/JS框架】CVE-2026-3854:GitHub Enterprise Server X-Stat注入XSS漏洞深度剖析与紧急修复指南
前端·javascript·github
计算机魔术师2 小时前
AMD砸82亿买下李飞飞,这次不卖芯片卖什么?
前端
hzxpaipai3 小时前
杭州企业官网怎么建设?从策划到上线的5步建站方法
运维·服务器·前端·网络
怕浪猫3 小时前
2026年金九银十,我面了22个前端
前端·javascript·面试
IT_陈寒3 小时前
Vue 这个响应式陷阱,我的头发都掉没了
前端·人工智能·后端
前端的日常3 小时前
一个人+AI做情侣食谱小程序,30天纯赚
前端·javascript·后端
庄园特聘拆椅狂魔4 小时前
Java 后端转全栈的第一课:从前端项目搭建到技术选
java·开发语言·前端
triumph_passion4 小时前
前端路由策略:Memory、Hash 与 History
前端