我正在尝试做类似于这个问题的事情。我有一个登录页面,表单检查提交的电子邮件是否有帐户;如果没有,我希望它重定向到注册页面:
const onSubmit = async (data) => {
const { email } = data;
const res = await checkUser(email)
.then(async (isUser) => {
if (isUser) {
// do proper authentication
} else {
redirect('/register');
}
})
}
对上一个问题的唯一赞成的答案说:“据我所知,
redirect
方法只能在服务器上使用”,然后继续建议使用useRouter
。现在,我可以做到这一点,但这是一个基于 NextJS 13 App-Router 的应用程序,与该答案中的建议相反,文档说,“redirect
可以在服务器组件、客户端组件、路由中使用处理程序和服务器操作。”所以,我觉得我应该使用redirect
。
不幸的是,它
throw
被调用的时候。现在,这种行为也被记录下来,并且是它应该做的。但是,它并没有真正重定向,而是被困在我的catch
块中。
问题的有效(即无效)示例可以在 CodeSandbox 中找到。
虽然比问题的 CodeSandbox 演示更详细,但我的实际代码如下所示,评论中提到了三种不同的尝试(a、b 和 c):
const onSubmit = async (data, toast) => {
const { email } = data;
const res = await checkUser(email)
.then(async (isUser) => {
if (isUser) {
const cb = await signIn('email', {
email: email,
callbackUrl: '/profile'
});
return cb;
} else {
redirect('/register'); // option a & b passes through to catch block below
// throw new Error('NFU'); // option (c)
}
})
.then((callback) => {
if (callback?.error) {
throw new Error(callback.error);
} else if (callback?.ok) {
toast.create({
title: 'Congratulations!',
description: `You're signed in!`,
status: 'success',
duration: 5000
});
// return true; // part of c, below
}
})
.catch(((error) => {
// option b, re-throw if we got a 404 from the checkUser call;
// unhandled runtime error
if(isRedirectError(error)) throw error;
//
// if ('NFU' === error.message) return false; // part of (c), below
toast.create({
title: 'Error',
description: error.message,
status: 'error',
duration: 5000
});
}))
// if (!res) redirect('/register') // option c, unhandled runtime error
}
在选项(a)中,我只是调用
redirect
,我认为这会起作用,但它却被困在 catch
中。选项 (b) 来自 5 月份 Vercel GitHub 上的此讨论,有关在服务器操作中使用 redirect
。那是在 App Router 离开实验状态之前,我所做的不是服务器操作;而是在 App Router 离开实验状态之前。尽管如此,我想我应该尝试一下:如果是 throw
,只需从 catch
内部重新重新isRedirectError
错误即可。但这会导致客户端出现未处理的运行时错误,而不是重定向。
最后(选项c),我尝试从承诺链中完全删除
redirect
,将res
设置为true
或false
,然后调用redirect
(如果为假);但这也会导致未处理的运行时错误。
我该如何进行这项工作?
为了完整起见,可能值得注意的是,这个
onSubmit
函数实际上传递给 handleSubmit
,因为表单是由 RHF 管理的。
此外,
onSubmit
函数是在组件外部定义的,因为整个事物都包装在 FormProvider
上下文中,其中 form
和 submit
按钮是共享 onSubmit
代码的不同组件。
我在这里使用服务器操作发布了一个解决方案。 https://github.com/vercel/next.js/discussions/57495#discussioncomment-8633077