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

集成Next Auth到Navbar后出现React Promise子元素错误求助

问题分析与解决

错误原因

你遇到的Error: Objects are not valid as a React child (found: [object Promise])错误,核心原因有两个:

  • React组件不能定义为async函数:async函数返回的是Promise对象,而React无法直接渲染Promise。你的Navbar组件被声明为async function Navbar,即使内部没有await操作,也会导致组件返回Promise,触发该错误。
  • 普通组件不能使用getServerSideProps:getServerSideProps是Next.js页面组件(pages目录下的文件)专属的服务端渲染方法,普通组件(如Navbar)导出该方法不会生效,还可能引发逻辑混乱。

修复步骤

1. 移除Navbar组件的async声明

将async function Navbar ({session})改为普通函数:

function Navbar ({session}) {
  // ... 原有组件逻辑
}

2. 移除组件中的getServerSideProps

把getServerSideProps从Navbar组件中删除,改为在使用Navbar的页面组件中获取session,再传递给Navbar。

例如,在pages目录下的某个页面文件中:

import Navbar from '../components/Navbar';
import { getServerSession } from "next-auth/next";
import options from './api/auth/[...nextauth]';

export async function getServerSideProps(context) {
  const session = await getServerSession(context.req, context.res, options);
  
  return {
    props: { session }
  };
}

export default function Home({ session }) {
  return (
    <>
      <Navbar session={session} />
      {/* 页面其他内容 */}
    </>
  );
}

3. (可选)使用客户端钩子获取session

如果不需要服务端渲染session,也可以在Navbar组件中直接使用useSession钩子获取:

import { useSession } from "next-auth/react";

function Navbar() {
  const { data: session } = useSession();

  return (
    {/* 原有组件逻辑,直接使用session */}
    <div className="hidden lg:flex lg:flex-1 lg:justify-end">
      {/* ... 其他链接 */}
      {session ? (
        <Link href="/api/auth/signout?callback=/">Logout</Link>
      ) : (
        <Link href="/api/auth/signin">Login</Link>
      )}
    </div>
  );
}

完整修复后的Navbar组件示例

import { Dialog, Disclosure, Popover, Transition, Fragment } from '@headlessui/react'
import {
  ArrowPathIcon,
  Bars3Icon,
  ChartPieIcon,
  CursorArrowRaysIcon,
  FingerPrintIcon,
  SquaresPlusIcon,
  XMarkIcon,
} from '@heroicons/react/24/outline'
import { ChevronDownIcon, PhoneIcon, PlayCircleIcon } from '@heroicons/react/20/solid'
import Link from 'next/link'
import { useSession } from "next-auth/react";

const products = [
  { name: 'Analytics', description: 'Get a better understanding of your traffic', href: '#', icon: ChartPieIcon },
  { name: 'Engagement', description: 'Speak directly to your customers', href: '#', icon: CursorArrowRaysIcon },
  { name: 'Security', description: 'Your customers’ data will be safe and secure', href: '#', icon: FingerPrintIcon },
  { name: 'Integrations', description: 'Connect with third-party tools', href: '#', icon: SquaresPlusIcon },
  { name: 'Automations', description: 'Build strategic funnels that will convert', href: '#', icon: ArrowPathIcon },
]
const callsToAction = [
  { name: 'Watch demo', href: '#', icon: PlayCircleIcon },
  { name: 'Contact sales', href: '#', icon: PhoneIcon },
]

function classNames(...classes: String[]) {
  return classes.filter(Boolean).join(' ')
}

function Navbar() {
  const { data: session } = useSession();

  return (
    <header style={{ backgroundColor: "#f85606" }}>
      <nav className="mx-auto flex max-w-7xl items-center justify-between py-6" aria-label="Global">
        <div className="flex lg:flex mr-10">
          <a href="#" className="-m-1.5 p-1.5">
            <span className="sr-only">Your Company</span>
            <img className="h-10 w-auto" src="https://icms-image.slatic.net/images/ims-web/e650d6ca-1841-4646-b0e9-4ddbf2beb731.png" alt="" />
          </a>
        </div>

        <Popover.Group className="hidden lg:flex">
          <Popover className="relative">
            <Popover.Button className="flex pt-2 items-center text-md font-semibold leading-6 text-white">
              Product
              <ChevronDownIcon className="h-5 w-5 flex-none text-white" aria-hidden="true" />
            </Popover.Button>

            <Transition
              as={Fragment}
              enter="transition ease-out duration-200"
              enterFrom="opacity-0 translate-y-1"
              enterTo="opacity-100 translate-y-0"
              leave="transition ease-in duration-150"
              leaveFrom="opacity-100 translate-y-0"
              leaveTo="opacity-0 translate-y-1"
            >
              <Popover.Panel className="absolute -left-8 top-full z-10 mt-3 w-screen max-w-md overflow-hidden rounded-3xl bg-white shadow-lg ring-1 ring-gray-900/5">
                <div className="p-4">
                  {products.map((item) => (
                    <div
                      key={item.name}
                      className="group relative flex items-center gap-x-6 rounded-lg p-4 text-sm leading-6 hover:bg-gray-50"
                    >
                      <div className="flex h-11 w-11 flex-none items-center justify-center rounded-lg bg-gray-50 group-hover:bg-white">
                        <item.icon className="h-6 w-6 text-gray-600 group-hover:text-indigo-600" aria-hidden="true" />
                      </div>
                      <div className="flex-auto">
                        <a href={item.href} className="block font-semibold text-gray-900">
                          {item.name}
                          <span className="absolute inset-0" />
                        </a>
                        <p className="mt-1 text-gray-600">{item.description}</p>
                      </div>
                    </div>
                  ))}
                </div>
                <div className="grid grid-cols-2 divide-x divide-gray-900/5 bg-gray-50">
                  {callsToAction.map((item) => (
                    <a
                      key={item.name}
                      href={item.href}
                      className="flex items-center justify-center gap-x-2.5 p-3 text-sm font-semibold leading-6 text-gray-900 hover:bg-gray-100"
                    >
                      <item.icon className="h-5 w-5 flex-none text-gray-400" aria-hidden="true" />
                      {item.name}
                    </a>
                  ))}
                </div>
              </Popover.Panel>
            </Transition>
          </Popover>

          <div style={{ width: "40rem" }} className="flex rounded-md shadow-sm ring-1 ring-inset ring-gray-300 focus-within:ring-2 focus-within:ring-inset focus-within:ring-indigo-600">
            <input
              type="text"
              name="username"
              id="username"
              autoComplete="username"
              className="block w-full flex-1 rounded-l-md border border-0 bg-white py-1.5 pl-1 text-gray-900 placeholder:text-gray-400 focus:outline-none sm:text-sm sm:leading-6"
              placeholder="janesmith"
            />
            <span className="flex select-none rounded-r-md bg-white items-center pl-3 text-orange-900 sm:text-sm">workcation.com/</span>
          </div>
        </Popover.Group>
        <div className="hidden lg:flex lg:flex-1 lg:justify-end">
          <Link href="/User" className="text-sm mx-2 font-semibold leading-6 text-gray-900">
            User Home
          </Link>
          <Link href="/" className="text-sm mx-2 font-semibold leading-6 text-gray-900">
            App Home
          </Link>
          <Link href="/User/Cart" className="text-sm mx-2 font-semibold leading-6 text-gray-900">
            User Cart
          </Link>
          <Link href="/admin" className="text-sm mx-2 font-semibold leading-6 text-gray-900">
            Admin
          </Link>
          {session ? (
            <Link href="/api/auth/signout?callback=/" className="text-sm mx-2 font-semibold leading-6 text-gray-900">
              Logout
            </Link>
          ) : (
            <Link href="/api/auth/signin" className="text-sm mx-2 font-semibold leading-6 text-gray-900">
              Login
            </Link>
          )}
        </div>
      </nav>
    </header>
  )
}
export default Navbar;

内容的提问来源于stack exchange,提问作者Muzammil Irshad

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 20:35:54