勇哥

勇哥开发之路

I build things on web.

Next.js 踩坑之 useSearchParams()

❗问题#

最近勇哥在做 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>Loading chat...</div>}>
      <ChatPageContent />
    </Suspense>
  );
}

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

加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。