Next.js 踩坑之 useSearchParams()

❗问题

最近勇哥在做 AI 对话应用的过程中，为了得到获取 URL 中的参数，使用了 useSearchParams 方法。
development 模式下一切正常，build 时却报错：

Copy
⨯ useSearchParams() should be wrapped in a suspense boundary at page "/".

❓原因

官方给出的解释是：
在没有 Suspense 边界的情况下通过 useSearchParams () 读取搜索参数将使整个页面进入客户端渲染。这可能会导致页面在客户端 JavaScript 加载之前一直空白。

因为勇哥用的是静态渲染， useSearchParams方法返回的是 URLSearchParams 接口的只读接口。而 URLSearchParams是要依赖于浏览器的，也就是说要等 window 对象加载完才能使用。

✔解决办法

官方推荐的解决办法也很简单：确保对 useSearchParams () 的调用被包裹在 Suspense 中。

修改之前，勇哥的 page.tsx 文件是这样的：

Copy
'use client';

...
import { useRouter, useSearchParams } from 'next/navigation'
import { SidebarProvider, SidebarInset } from "@/components/ui/sidebar"
...

// 主页面组件
export default function Page() {
const router = useRouter()
const urlParams = useSearchParams()
// ... 其他状态和逻辑

return (
<SidebarProvider>
<AppSidebar />
<SidebarInset>
...
</SidebarInset>
</SidebarProvider>
);
}

修改之后：

Copy
'use client';

import { Suspense } from "react"
import { useRouter, useSearchParams } from 'next/navigation'
import { SidebarProvider, SidebarInset } from "@/components/ui/sidebar"

// 新建一个包装组件来处理所有客户端逻辑
function ChatPageContent() {
// ... 原来的状态和逻辑
const router = useRouter()
const urlParams = useSearchParams()
// ... 其他状态和逻辑

return (
<SidebarProvider>
<AppSidebar />
<SidebarInset>
...
</SidebarInset>
</SidebarProvider>
);
}
}

// 主页面组件
export default function Page() {
// 在包装组件外面加上 <Suspense />
return (
<Suspense fallback={ Loading chat... }>
<ChatPageContent />
</Suspense>
);
}

将使用到 useSearchParams 的客户端组件包装在 <Suspense/> 中。这种情况下，路由中的一部分会被静态渲染，而使用 useSearchParams 的动态部分则在客户端等 window 对象可用后再渲染。