我正在将 Next.js 14 与应用程序路由器一起使用。
我有两个服务器组件:
/products
显示多个产品/products/{id}
。在
/products/{id}
上,我通过服务器操作检查 id
在我的产品数据库中是否可用,然后渲染产品。
如果产品不可用,我想将用户重定向回
/products
并显示一条提示消息,表明未找到产品。
重定向非常简单:
import { redirect } from 'next/navigation'
async function getNoProduct() {
return null
}
export default async function RedirectFromPage() {
let res = await getNoProduct()
if (!res === null) {
redirect('/products')
}
return (
<div>
<p>Hello SO</p>
</div>
)
}
但是,我在实现 toast 消息时遇到了困难(通过 shadcn 使用 sonner toast)。
像下面这样直接添加toast是不行的,因为
/products/{id}
是一个服务器组件,而toast依赖于useEffect,
例如
import { redirect } from 'next/navigation'
import { useToast } from '@/components/ui/use-toast'
async function getNoProduct() {
return null
}
export default async function RedirectFromPage() {
const { toast } = useToast()
let res = await getNoProduct()
if (!res === null) {
// Show toast
toast({
title: 'Error',
description: 'Product not found',
})
redirect('/products')
}
return (
<div>
<p>Hello SO</p>
</div>
)
}
会导致错误
Error: useState only works in Client Components. Add the "use client" directive at the top of the file to use it. Read more: https://nextjs.org/docs/messages/react-client-hook-in-server-component
基于与服务器操作相关的另一个SO问题(here),我认为我可以使用cookie将错误传达给
/products
,然后渲染使用toast的客户端组件,但遇到问题,因为我可以触发这些服务器仅来自客户端组件的操作。
我应该如何处理这个问题? toast 是这里的组件类型错误还是有更好的方法来做到这一点?
我的理解是 toast 包是为客户端设计的。对于服务器端,我认为您可以创建一个 loading.tsx 页面,nextjs 将显示加载页面,然后显示预期页面。如果它是服务器渲染页面内的客户端组件,您应该能够使用 React Suspense 将客户端组件包装在服务器渲染页面中