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

useFormStatus过早重置pending状态问题求助

问题:useFormStatus的pending状态提前变为false,未等待服务器动作完成

我有如下表单组件:

import { sleepAction } from "@/actions/serveractions";
import SubmitUseFormStatus from "@/components/SubmitButton";

export default function Home() {
  return (
    <div className="">
      <form action={sleepAction}>
        <SubmitUseFormStatus />
      </form>
    </div>
  );
}

对应的客户端提交组件:

"use client";
import { Button } from "@nextui-org/button";
import { Input } from "@nextui-org/input";
import { useFormStatus } from "react-dom";

export default function SubmitUseFormStatus() {
  const { pending } = useFormStatus();
  return (
    <div className="flex flex-col gap-4 w-48">
      <Input
        name="time"
        type="number"
        placeholder="Time in seconds"
        defaultValue={"4000"}
      />
      <Button type="submit" color="primary">
        {pending ? "Submitting ..." : "Submit"}
      </Button>
    </div>
  );
}

服务器动作sleepAction会等待指定时长后返回:

"use server";

export async function sleepAction(formData: FormData): Promise<void> {
  const sleeptime = +(formData.get("time") as string);

  console.log(`sleepaction ${sleeptime}`);
  console.log("start ...");
  await sleep(sleeptime);
  console.log("... end");

  return;
}

function sleep(ms: number): Promise<void> {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

点击提交按钮后,sleepAction被调用并会在4000ms后返回,但useFormStatus返回的pending仅维持500ms就变为false,此时sleepAction()仍在运行,导致提交状态指示器失效。想知道哪里操作有误?另外使用useActionState()的类似示例能正常工作,是不是useFormStatus在表单提交后立即把pending设为false,没有等待服务器动作响应?


问题原因

这是因为原生<form>标签调用服务器动作时,默认会触发页面刷新/导航。表单提交后,浏览器会立即加载新页面,当前客户端组件被卸载,useFormStatus的pending状态随之变为false,但服务器端的sleepAction还在执行。

而useActionState是专为无刷新表单提交设计的API,它会在客户端保留组件状态直到服务器响应返回,因此能正常显示提交状态。

解决方法

要让useFormStatus正确反映服务器动作的整个生命周期,需使用Next.js的无刷新表单方案:

  1. 从next/navigation导入Form组件,替换原生<form>标签:
import { sleepAction } from "@/actions/serveractions";
import SubmitUseFormStatus from "@/components/SubmitButton";
import { Form } from "next/navigation";

export default function Home() {
  return (
    <div className="">
      <Form action={sleepAction}>
        <SubmitUseFormStatus />
      </Form>
    </div>
  );
}
  1. 确保提交组件保持客户端组件身份(已添加"use client";指令,无需修改)。

修改后,表单提交会以无刷新方式进行,useFormStatus的pending状态会持续到sleepAction执行完成,提交按钮的状态也会正确显示"Submitting ..."直到动作结束。

另外注意:useFormStatus必须是表单的直接子组件或后代组件,你的代码已满足该要求,无需调整组件结构。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 11:22:05