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的无刷新表单方案:
- 从
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> ); }
- 确保提交组件保持客户端组件身份(已添加
"use client";指令,无需修改)。
修改后,表单提交会以无刷新方式进行,useFormStatus的pending状态会持续到sleepAction执行完成,提交按钮的状态也会正确显示"Submitting ..."直到动作结束。
另外注意:useFormStatus必须是表单的直接子组件或后代组件,你的代码已满足该要求,无需调整组件结构。
内容的提问来源于stack exchange,提问作者Robert Hufsky
相关产品推荐
相关产品推荐

