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

Next.js表单提交时状态未就绪,如何保证数据库记录完整?

解决方法

核心问题在于你在Promise.all的每个异步回调里单独更新urls状态,而状态更新是异步的,同时then块里捕获的是当前闭包中的urls值(初始空数组),自然拿不到最新的上传结果。另外多次调用setUrls会触发多次重渲染和useEffect,完全没必要。

直接在Promise.all中收集所有上传后的url,一次性处理即可:

const [isPending, startTransition] = useTransition();
const [urls, setUrls] = useState<string[]>([]);
const { edgestore } = useEdgeStore();

const onSubmit = async (values: z.infer<typeof formSchema>) => {
  try {
    // 用Promise.all直接收集所有上传后的url,不需要逐次更新状态
    const uploadedUrls = await Promise.all(
      filesToAdd.map(async (addedFileState) => {
        const res = await edgestore.publicFiles.upload({
          file: addedFileState.file as File,
        });
        return res.url; // 直接返回url,统一收集
      })
    );
    
    // 一次性更新状态(可选,如果你后续还需要用到这个状态的话)
    setUrls(uploadedUrls);
    
    // 直接用收集到的uploadedUrls创建记录,不需要等状态更新
    startTransition(() => {
      createRecord({ imagesUrls: uploadedUrls, name: values.name });
    });
  } catch {
    toast.error("Something went wrong");
  }
};

这样做的好处:

  • 避免了异步状态更新带来的闭包问题,直接使用同步收集的uploadedUrls,确保创建数据库记录时拿到完整的url列表
  • 只触发一次状态更新(如果需要的话),不会多次调用setUrls和useEffect
  • 代码逻辑更清晰,减少不必要的状态更新

如果你确实需要依赖urls状态来触发后续操作(比如上传完成后在页面展示),可以配合useEffect,但只在urls长度和filesToAdd长度一致时执行:

useEffect(() => {
  // 只有当urls的数量和上传的文件数量一致时,才执行创建记录操作
  if (urls.length === filesToAdd.length && urls.length > 0) {
    startTransition(() => {
      createRecord({ imagesUrls: urls, name: values.name });
    });
  }
}, [urls, filesToAdd.length, createRecord, values.name, startTransition]);

不过更推荐第一种方案,逻辑更直接,不需要依赖状态的异步更新。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 00:12:11