You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

shadcn/ui Dialog与Form组件:handleOpenChange先于onSubmit触发问题求助

解决shadcn/ui Dialog与react-hook-form提交时表单提前重置的问题

问题原因:这是组件的预期行为

shadcn/ui的DialogClose组件核心逻辑就是触发Dialog的关闭(调用onOpenChange并传入false),无论它包裹的按钮是什么类型。点击被DialogClose包裹的Submit按钮时,事件触发顺序是:

  1. DialogClose的点击事件先执行,调用handleOpenChange(false)
  2. handleOpenChange里执行form.reset()重置表单
  3. 表单的onSubmit才触发,但此时表单数据已被清空

解决方案

核心思路是拆分提交与关闭逻辑,让表单提交完成后再处理弹窗关闭和表单重置,而非通过DialogClose直接绑定提交按钮。

修改后的代码示例

const form = useForm<z.infer<typeof formSchema>>({
  resolver: zodResolver(formSchema),
  defaultValues: {
    name: 'Figma',
    category: 'Software',
    version: '1.0',
    location: 'Taipei',
    status: 'Available',
  },
});

const onSubmit = (values: z.infer<typeof formSchema>) => {
  // 优先完成表单提交逻辑
  const newItems = { ...values };
  setItems((prevItems) => [...prevItems, newItems]);
  
  // 提交成功后手动关闭弹窗并重置表单
  setIsOpen(false);
  form.reset();
};

const handleOpenChange = (open) => {
  setIsOpen(open);
  
  // 仅在非提交状态下关闭弹窗时重置表单
  if (!open && !form.formState.isSubmitting) {
    form.reset();
  }
};

return (
  <Dialog open={isOpen} onOpenChange={handleOpenChange}>
    <DialogContent>
      <Form {...form}>
        <form onSubmit={form.handleSubmit(onSubmit)}>
          <input type="text" {...form.register("exampleFieldName")} />
          {/* 提交按钮不再用DialogClose包裹 */}
          <Button type="submit">Submit</Button>
          {/* 关闭按钮保留DialogClose逻辑 */}
          <DialogClose asChild>
            <Button type="button" variant="secondary">
              Close
            </Button>
          </DialogClose>
        </form>
      </Form>
    </DialogContent>
  </Dialog>
)

关键改动说明

  • 提交按钮:移除DialogClose包裹,改为在onSubmit函数末尾手动关闭弹窗并重置表单,确保提交逻辑优先执行。
  • 关闭按钮:保留DialogClose,同时在handleOpenChange中增加form.formState.isSubmitting判断,避免提交过程中误触发表单重置。

内容的提问来源于stack exchange,提问作者wyc

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 07:17:40