如何在Next.js中实现表单提交时按钮文本切换为Processing的功能
在Next.js中实现登录按钮提交状态切换
你不能直接在Next.js中使用react-router-dom的useNavigation钩子,因为Next.js有独立的路由体系。根据你使用的是App Router(13+)还是Pages Router,可以用以下方案复刻需求:
一、App Router(13+)实现方式
1. 使用Next.js内置的useNavigation钩子
Next.js的App Router提供了next/navigation下的useNavigation,可以用来检测路由导航/数据加载状态,用法和你之前的React实现类似:
import { useNavigation } from 'next/navigation'; export default function LoginForm() { const navigation = useNavigation(); const isSubmitting = navigation.state === 'loading'; const handleLogin = async (e) => { e.preventDefault(); // 执行登录逻辑,比如调用后端API await fetch('/api/login', { method: 'POST', body: new FormData(e.target) }); // 登录完成后可跳转至目标页面 }; return ( <form onSubmit={handleLogin}> <input type="email" name="email" placeholder="邮箱" required /> <input type="password" name="password" placeholder="密码" required /> <button type="submit" disabled={isSubmitting}> {isSubmitting ? 'Processing...' : 'Login'} </button> </form> ); }
2. 结合Server Actions使用useFormStatus
如果你的登录逻辑采用Next.js的Server Actions,用useFormStatus可以更精准地监听表单提交状态:
'use client'; // 必须标记为客户端组件 import { useFormStatus } from 'react-dom'; // 定义Server Action(可放在服务器组件或单独文件) async function loginAction(formData) { 'use server'; // 模拟登录异步操作 await new Promise(resolve => setTimeout(resolve, 1500)); // 实际场景中处理用户验证、会话创建等逻辑 } function LoginButton() { const { pending } = useFormStatus(); return ( <button type="submit" disabled={pending}> {pending ? 'Processing...' : 'Login'} </button> ); } export default function LoginForm() { return ( <form action={loginAction}> <input type="email" name="email" placeholder="邮箱" required /> <input type="password" name="password" placeholder="密码" required /> <LoginButton /> </form> ); }
二、Pages Router实现方式
Pages Router没有内置的提交状态检测钩子,最直接的方式是手动管理本地状态:
import { useState } from 'react'; import { useRouter } from 'next/router'; export default function LoginPage() { const [isSubmitting, setIsSubmitting] = useState(false); const router = useRouter(); const handleLogin = async (e) => { e.preventDefault(); setIsSubmitting(true); try { // 调用登录API const res = await fetch('/api/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: e.target.email.value, password: e.target.password.value }) }); if (res.ok) { await router.push('/dashboard'); // 登录成功跳转 } else { alert('登录失败,请检查账号密码'); } } catch (err) { console.error('登录请求出错:', err); alert('网络异常,请稍后重试'); } finally { setIsSubmitting(false); // 无论成败,恢复按钮状态 } }; return ( <form onSubmit={handleLogin}> <input type="email" name="email" placeholder="邮箱" required /> <input type="password" name="password" placeholder="密码" required /> <button type="submit" disabled={isSubmitting}> {isSubmitting ? 'Processing...' : 'Login'} </button> </form> ); }
通用注意事项
- 给按钮添加
disabled属性,避免用户重复提交 - 优先使用表单的
onSubmit事件处理登录,而非按钮的onClick,符合表单默认交互逻辑
内容的提问来源于stack exchange,提问作者D. Rattansingh
相关产品推荐
相关产品推荐

