Next.js 13 App Router中react-hook-form的redirect失效问题求助
解决方案:Next.js 13 App Router + React Hook Form 登录跳转注册页
在Next.js 13 App Router的客户端组件中,redirect函数通过抛出特殊错误实现跳转,一旦被try/catch捕获就会失效,且直接在非组件顶层调用容易引发未处理运行时错误。推荐使用客户端导航API useRouter().push() 替代,以下是完整实现方案:
1. 核心逻辑:用useRouter替代redirect
在表单处理的客户端组件中,使用Next.js提供的useRouter进行导航,它不会抛出错误,可安全用于条件判断或错误处理流程中。
2. 完整代码示例
父组件(LoginPage):管理表单逻辑与跳转
'use client' import { FormProvider, useForm } from 'react-hook-form' import { useRouter } from 'next/navigation' import LoginFormFields from './LoginFormFields' import SubmitButton from './SubmitButton' export default function LoginPage() { const router = useRouter() const formMethods = useForm({ defaultValues: { email: '', password: '' } }) const { handleSubmit } = formMethods // 表单提交处理函数 const onSubmit = async (formData) => { try { // 调用后端接口检查邮箱是否存在 const checkRes = await fetch('/api/check-user-email', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: formData.email }) }) const checkResult = await checkRes.json() if (!checkResult.userExists) { // 邮箱不存在,跳转到注册页 router.push('/register') return } // 邮箱存在,执行登录逻辑 const loginRes = await fetch('/api/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(formData) }) if (loginRes.ok) { // 登录成功跳转到首页 router.push('/') } else { console.error('登录失败:', await loginRes.text()) } } catch (err) { console.error('请求出错:', err) } } return ( <FormProvider {...formMethods}> <form onSubmit={handleSubmit(onSubmit)} className="space-y-4"> <LoginFormFields /> <SubmitButton /> </form> </FormProvider> ) }
表单字段组件(LoginFormFields):渲染输入框
'use client' import { useFormContext } from 'react-hook-form' export default function LoginFormFields() { const { register } = useFormContext() return ( <> <div> <label htmlFor="email">邮箱</label> <input id="email" type="email" {...register('email', { required: '请输入邮箱' })} className="w-full mt-1 p-2 border" /> </div> <div> <label htmlFor="password">密码</label> <input id="password" type="password" {...register('password', { required: '请输入密码' })} className="w-full mt-1 p-2 border" /> </div> </> ) }
提交按钮组件(SubmitButton):独立渲染提交按钮
'use client' export default function SubmitButton() { return ( <button type="submit" className="w-full p-2 bg-blue-500 text-white rounded" > 登录 </button> ) }
关键说明
- 为什么不用
redirect:redirect依赖抛出错误实现跳转,若被try/catch捕获则跳转失效;而useRouter().push()是客户端导航的常规API,无错误抛出问题,适合在条件判断中直接调用。 - FormProvider传递逻辑:通过
FormProvider将表单方法传递给子组件,确保输入框和提交按钮共享同一个表单状态,符合React Hook Form的最佳实践。
内容的提问来源于stack exchange,提问作者philolegein
相关产品推荐
相关产品推荐

