集成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
相关产品推荐
相关产品推荐

