如何在Next.js Server Action中实现表单加载状态显示
在Next.js 13/14 Server Action中获取表单加载状态的方案
由于Server Component无法使用React Hooks,要实现提交按钮的加载UI,可采用以下两种实用方案:
方案一:抽离表单为客户端组件(官方推荐)
将包含表单的部分单独做成客户端组件,利用useFormStatus Hook获取加载状态。
实现步骤:
- 创建客户端组件
SignUpForm.tsx:
'use client'; import { useFormStatus } from 'react-dom'; import { cookies, redirect } from 'next/navigation'; import { createClient } from '@/utils/supabase'; // 替换为你的Supabase创建路径 // 封装带状态的提交按钮 function SubmitButton() { const { pending } = useFormStatus(); return ( <input type="submit" value={pending ? '提交中...' : 'Submit'} disabled={pending} /> ); } export default function SignUpForm() { return ( <form action={async (formData) => { 'use server'; const email = formData.get("email") as string; const password = formData.get("password") as string; const cookieStore = cookies(); const supabase = createClient(cookieStore); // 执行Supabase注册逻辑 const { error } = await supabase.auth.signUp({ email, password }); if (error) throw error; return redirect("/dashboard"); }}> <input type="email" name="email" placeholder="Email" required /> <input type="password" name="password" placeholder="Password" required /> <SubmitButton /> </form> ); }
- 在Server Component的
page.tsx中引入该组件:
import SignUpForm from './SignUpForm'; export default async function Page() { return ( <div> sign up form <SignUpForm /> </div> ); }
说明:useFormStatus必须作为表单的子组件使用,它会自动关联父表单的Server Action执行状态,pending为true时表示Action正在处理。
方案二:用useTransition手动管理状态
若不想改动整体组件结构,可在客户端组件中用useTransition包裹Server Action调用,手动控制加载状态。
示例代码:
'use client'; import { useTransition } from 'react'; import { cookies, redirect } from 'next/navigation'; import { createClient } from '@/utils/supabase'; async function signUp(formData: FormData) { 'use server'; const email = formData.get("email") as string; const password = formData.get("password") as string; const cookieStore = cookies(); const supabase = createClient(cookieStore); const { error } = await supabase.auth.signUp({ email, password }); if (error) throw error; return redirect("/dashboard"); } export default function SignUpForm() { const [isPending, startTransition] = useTransition(); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); const formData = new FormData(e.currentTarget); startTransition(() => { signUp(formData); }); }; return ( <form onSubmit={handleSubmit}> <input type="email" name="email" placeholder="Email" required /> <input type="password" name="password" placeholder="Password" required /> <input type="submit" value={isPending ? '提交中...' : 'Submit'} disabled={isPending} /> </form> ); }
同样在page.tsx中引入该客户端组件即可。
注意:两种方案都需要将状态管理逻辑放在客户端组件中,这是Next.js App Router中Server Component的核心限制决定的。
内容的提问来源于stack exchange,提问作者Arrofi Reza Satria
相关产品推荐
相关产品推荐

