You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vercel部署项目报错:/auth-callback页面需将useSearchParams()包裹在Suspense边界中

解决Next.js部署到Vercel时的useSearchParams Suspense边界错误

部署Next.js项目到Vercel时,/auth-callback页面触发错误:useSearchParams()应包裹在Suspense边界内。这是因为在App Router模式下,useSearchParams是客户端专属钩子,若在服务端组件中使用会触发CSR回退,必须通过Suspense或客户端组件标记来处理。

解决办法

办法一:将页面标记为客户端组件(推荐)

直接在页面顶部添加'use client';指令,让整个页面在客户端渲染,无需额外Suspense包裹,适配页面本身的客户端操作逻辑。

修改后的完整代码:

'use client';
import React, { useEffect } from 'react';
import { useRouter, useSearchParams } from "next/navigation";
import { trpc } from "../_trpc/client";
import { Loader2 } from "lucide-react";

const Page = () => {
  const router = useRouter();
  const searchParams = useSearchParams();
  const origin = searchParams.get("origin");

  const { data, error, isLoading } = trpc.authCallback.useQuery(undefined, {
    retry: true,
    retryDelay: 500,
  });

  useEffect(() => {
    if (error && error.data?.code === "UNAUTHORIZED") {
      router.push("/sign-in");
    } else if (!isLoading && !error) {
      router.push(origin ? `/${origin}` : "/dashboard");
    }
  }, [isLoading, error, origin, router]);

  return (
    <div className="w-full mt-24 flex justify-center">
      <div className="flex flex-col items-center gap-2">
        <Loader2 className="h-8 w-8 animate-spin text-zinc-800" />
        <h3 className="font-semibold text-xl">
          Setting up your account...
        </h3>
        <p>You will be redirected automatically.</p>
      </div>
    </div>
  );
};

export default Page;

办法二:用Suspense包裹客户端逻辑组件

若不想将整个页面设为客户端组件,可拆分逻辑到子组件,再用Suspense包裹该子组件。

  1. 创建客户端子组件AuthCallbackClient.js:
'use client';
import React, { useEffect } from 'react';
import { useRouter, useSearchParams } from "next/navigation";
import { trpc } from "../_trpc/client";
import { Loader2 } from "lucide-react";

export const AuthCallbackClient = () => {
  const router = useRouter();
  const searchParams = useSearchParams();
  const origin = searchParams.get("origin");

  const { data, error, isLoading } = trpc.authCallback.useQuery(undefined, {
    retry: true,
    retryDelay: 500,
  });

  useEffect(() => {
    if (error && error.data?.code === "UNAUTHORIZED") {
      router.push("/sign-in");
    } else if (!isLoading && !error) {
      router.push(origin ? `/${origin}` : "/dashboard");
    }
  }, [isLoading, error, origin, router]);

  return (
    <div className="flex flex-col items-center gap-2">
      <Loader2 className="h-8 w-8 animate-spin text-zinc-800" />
      <h3 className="font-semibold text-xl">
        Setting up your account...
      </h3>
      <p>You will be redirected automatically.</p>
    </div>
  );
};
  1. 修改原页面,用Suspense包裹子组件:
import React, { Suspense } from 'react';
import { AuthCallbackClient } from './AuthCallbackClient';

const Page = () => {
  return (
    <div className="w-full mt-24 flex justify-center">
      <Suspense fallback={
        <div className="flex flex-col items-center gap-2">
          <Loader2 className="h-8 w-8 animate-spin text-zinc-800" />
          <h3 className="font-semibold text-xl">Loading...</h3>
        </div>
      }>
        <AuthCallbackClient />
      </Suspense>
    </div>
  );
};

export default Page;

说明

优先选第一种办法,因为页面核心逻辑(读取URL参数、路由跳转、调用trpc客户端钩子)都是客户端操作,直接标记为客户端组件更简洁,无需额外拆分组件。

内容的提问来源于stack exchange,提问作者Rowny Robert

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 23:12:46