Next.js getStaticProps页面引入Navbar组件报元素类型无效错误

问题背景
- 开发Next.js应用时,使用
getStaticProps的页面引入Navbar组件后,控制台抛出「element type is invalid(元素类型无效)」错误 - 同一个Navbar组件在未配置
getStaticProps/getServerSideProps的普通页面中可正常渲染 - Navbar为常规导航栏组件,基于TailwindCSS编写,无数据请求逻辑,内部引入了
@headlessui/react的Popover、Transition组件和React的Fragment;报错页面暂未使用TailwindCSS,对应调用的API接口运行正常。
报错页面代码
import {Navbar} from "../components/schema/Navbar" export default function Dope({users}) { console.log(users) return ( <div> {/* <Navbar /> */} <main> <div> {users.length === 0 ? ( <h2>No users added</h2> ) : ( users.map((user, i) => ( <h1 key={i}>{user}</h1> )) )} </div> </main> </div> ) } export async function getStaticProps(ctx) { // get the current environment let dev = process.env.NODE_ENV !== 'production'; let { DEV_URL, PROD_URL } = process.env; // request posts from api let response = await fetch(`${dev ? DEV_URL : PROD_URL}/api/users`); // extract the data let data = await response.json(); return { props : { users : data['message'] } } }
Navbar组件源码
import { Fragment } from 'react' import { Popover, Transition } from '@headlessui/react' import { BookmarkAltIcon, CalendarIcon, ChartBarIcon, CursorClickIcon, MenuIcon, RefreshIcon, ShieldCheckIcon, SupportIcon, ViewGridIcon, XIcon, } from '@heroicons/react/outline' import { ChevronDownIcon } from '@heroicons/react/solid' const features = [ { name: 'Airdrops', href: '#', description: 'Get a better understanding of where your traffic is coming from.', icon: ChartBarIcon, }, { name: 'Updates', href: '#', description: 'Speak directly to your customers in a more meaningful way.', icon: CursorClickIcon, }, { name: 'Airdrop Tracer', href: '#', description: "Your customers' data will be safe and secure.", icon: ShieldCheckIcon }, { name: 'FAQ', href: '#', description: "Connect with third-party tools that you're already using.", icon: ViewGridIcon, }, { name: 'About', href: '#', description: 'Build strategic funnels that will drive your customers to convert', icon: RefreshIcon, }, ] const resources = [ { name: 'Help Center', description: 'Get all of your questions answered in our forums or contact support.', href: '#', icon: SupportIcon, }, { name: 'Guides', description: 'Learn how to maximize our platform to get the most out of it.', href: '#', icon: BookmarkAltIcon, }, { name: 'Events', description: 'See what meet-ups and other events we might be planning near you.', href: '#', icon: CalendarIcon, }, { name: 'Security', description: 'Understand how we take your privacy seriously.', href: '#', icon: ShieldCheckIcon }, ] function classNames(...classes) { return classes.filter(Boolean).join(' ') } export default function Navbar() { return ( <div className="relative bg-gray-50"> <Popover className="relative bg-white shadow"> <div className="max-w-7xl mx-auto px-4 sm:px-6"> <div className="flex justify-between items-center py-6 md:justify-start md:space-x-10"> <div className="flex justify-start lg:w-0 lg:flex-1"> <a href="#"> <span className="sr-only">Workflow</span> <img className="h-8 w-auto sm:h-10" src="https://tailwindui.com/img/logos/workflow-mark-indigo-600.svg" alt="" /> </a> </div> <div className="-mr-2 -my-2 md:hidden"> <Popover.Button className="bg-white rounded-md p-2 inline-flex items-center justify-center text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-500"> <span className="sr-only">Open menu</span> <MenuIcon className="h-6 w-6" aria-hidden="true" /> </Popover.Button> </div> <Popover.Group as="nav" className="hidden md:flex space-x-10"> <a href="#" className="text-base font-medium text-gray-500 hover:text-gray-900"> Airdrops </a> <a href="#" className="text-base font-medium text-gray-500 hover:text-gray-900"> Potential Airdrops </a> <a href="#" className="text-base font-medium text-gray-500 hover:text-gray-900"> Airdrop Tracer </a> <Popover className="relative"> {({ open }) => ( <> <Popover.Button className={classNames( open ? 'text-gray-900' : 'text-gray-500', 'group bg-white rounded-md inline-flex items-center text-base font-medium hover:text-gray-900 focus:outline-none' )} > <span>More</span> <ChevronDownIcon className={classNames( open ? 'text-gray-600' : 'text-gray-400', 'ml-1 mt-2 h-5 w-5 group-hover:text-gray-500' )} 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-1/2 z-10 transform -translate-x-1/2 mt-3 px-2 w-screen max-w-md sm:px-0"> <div className="rounded-lg shadow-lg ring-1 ring-black ring-opacity-5 overflow-hidden"> <div className="relative grid gap-6 bg-white px-5 py-6 sm:gap-8 sm:p-8"> {resources.map((item) => ( <a key={item.name} href={item.href} className="-m-3 p-3 flex items-start rounded-lg hover:bg-gray-50" > <item.icon className="flex-shrink-0 h-6 w-6 text-indigo-600" aria-hidden="true" /> <div className="ml-4"> <p className="text-base font-medium text-gray-900">{item.name}</p> <p className="mt-1 text-sm text-gray-500">{item.description}</p> </div> </a> ))} </div> </div> </Popover.Panel> </Transition> </> )} </Popover> </Popover.Group> <div className="hidden md:flex items-center justify-end md:flex-1 lg:w-0"> <a href="#" className="whitespace-nowrap text-base font-medium text-gray-500 hover:text-gray-900"> Sign in </a> <a href="#" className="ml-8 whitespace-nowrap inline-flex items-center justify-center px-4 py-2 border border-transparent rounded-md shadow-sm text-base font-medium text-white bg-indigo-600 hover:bg-indigo-700" > Sign up </a> </div> </div> </div> <Transition as={Fragment} enter="duration-200 ease-out" enterFrom="opacity-0 scale-95" enterTo="opacity-100 scale-100" leave="duration-100 ease-in" leaveFrom="opacity-100 scale-100" leaveTo="opacity-0 scale-95" > <Popover.Panel focus className="absolute top-0 inset-x-0 z-10 p-2 transition transform origin-top-right md:hidden" > <div className="rounded-lg shadow-lg ring-1 ring-black ring-opacity-5 bg-white divide-y-2 divide-gray-50"> <div className="pt-5 pb-6 px-5"> <div className="flex items-center justify-between"> <div> <img className="h-8 w-auto" src="https://tailwindui.com/img/logos/workflow-mark-indigo-600.svg" alt="Workflow" /> </div> <div className="-mr-2"> <Popover.Button className="bg-white rounded-md p-2 inline-flex items-center justify-center text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-500"> <span className="sr-only">Close menu</span> <XIcon className="h-6 w-6" aria-hidden="true" /> </Popover.Button> </div> </div> <div className="mt-6"> <nav className="grid gap-y-8"> {features.map((item) => ( <a key={item.name} href={item.href} className="-m-3 p-3 flex items-center rounded-md hover:bg-gray-50" > <item.icon className="flex-shrink-0 h-6 w-6 text-indigo-600" aria-hidden="true" /> <span className="ml-3 text-base font-medium text-gray-900">{item.name}</span> </a> ))} </nav> </div> </div> <div className="py-6 px-5 space-y-6"> <div> <a href="#" className="w-full flex items-center justify-center px-4 py-2 border border-transparent rounded-md shadow-sm text-base font-medium text-white bg-indigo-600 hover:bg-indigo-700" > Sign up </a> <p className="mt-6 text-center text-base font-medium text-gray-500"> Existing customer? <a href="#" className="text-indigo-600 hover:text-indigo-500"> Sign in </a> </p> </div> </div> </div> </Popover.Panel> </Transition> </Popover> </div> ) }
报错原因
核心问题是ES模块的导入方式和组件导出方式不匹配:
- Navbar组件使用默认导出语法:
export default function Navbar() {} - 报错页面中使用了命名导入语法:
import {Navbar} from "../components/schema/Navbar" - 这种写法会导致导入的
Navbar变量值为undefined,React尝试将undefined作为组件渲染时,就会触发「element type is invalid」错误。
该报错和页面是否使用getStaticProps/getServerSideProps、是否编写TailwindCSS样式没有关联。普通页面能正常渲染Navbar,是因为那些页面中使用了正确的默认导入写法。
修复方案
将页面顶部的Navbar导入语句修改为默认导入格式即可:
// 错误的命名导入 // import {Navbar} from "../components/schema/Navbar" // 正确的默认导入 import Navbar from "../components/schema/Navbar"
修改后取消<Navbar />的代码注释,组件即可正常渲染。
补充排查:如果修改导入后仍存在同类报错,可检查项目中
@headlessui/react、@heroicons/react的版本是否兼容,确认所有引入的图标组件、Headless UI子组件都正确导出且存在。
内容的提问来源于stack exchange,提问作者risky last
相关产品推荐
相关产品推荐

