❗問題#
最近勇哥在做 AI 對話應用的過程中,為了得到獲取 URL 中的參數,使用了 useSearchParams 方法。development 模式下一切正常,build 時卻報錯:
⨯ useSearchParams() should be wrapped in a suspense boundary at page "/".
❓原因#
官方給出的解釋是:
在沒有 Suspense 邊界的情況下通過 useSearchParams () 讀取搜索參數將使整個頁面進入客戶端渲染。這可能會導致頁面在客戶端 JavaScript 加載之前一直空白。
因為勇哥用的是靜態渲染, useSearchParams
方法返回的是 URLSearchParams
接口的只讀接口。而 URLSearchParams
是要依賴於瀏覽器的,也就是說要等 window 對象加載完才能使用。
✔解決辦法#
官方推薦的解決辦法也很簡單:確保對 useSearchParams () 的調用被包裹在 Suspense
中。
修改之前,勇哥的 page.tsx 文件是這樣的:
'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>
);
}
修改之後:
'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={<div>加載聊天中...</div>}>
<ChatPageContent />
</Suspense>
);
}
將使用到 useSearchParams
的客戶端組件包裝在 <Suspense/>
中。在這種情況下,路由中的一部分會被靜態渲染,而使用 useSearchParams
的動態部分則在客戶端等 window 對象可用後再渲染。