Next.js组件无法作为JSX组件使用,移动端菜单故障求助
解决Next.js中移动端菜单组件报错及层级问题
错误根源
- 组件无JSX返回:Navbar组件内部定义了MobileMenu,但函数末尾未返回任何JSX内容,导致组件无法被正确渲染,触发"Cannot be used as a JSX component"错误。
- 冗余依赖与语法错误:导入了多个未使用的模块(如useEffect、react-spring相关API),可能引发编译冲突;部分类名存在拼写错误(如
dark:text-gray-40应为dark:text-gray-400)。
修复步骤
1. 让Navbar返回MobileMenu组件
在Navbar函数末尾添加返回语句,确保组件输出合法JSX:
export default function Navbar(props) { // ... 原有代码 ... const MobileMenu = () => { // ... MobileMenu内部代码 ... } // 新增:返回MobileMenu组件 return <MobileMenu />; }
2. 修复类名拼写错误
找到Disclosure.Panel内的dark:text-gray-40,修改为完整的dark:text-gray-400:
<div className="text-xl font-serif hover:text-blue-500 dark:text-gray-400 order-2 -ml-4 mt-4 flex w-full flex-col items-center justify-start md:hidden">
3. 移除未使用的依赖
删除代码中未用到的导入,减少潜在编译冲突:
// 保留必要导入,移除冗余项 import { Fragment, useState } from "react"; import { Disclosure } from "@headlessui/react"; import Container from "@/components/container"; import Link from "next/link"; import Image from "next/image"; import { urlForImage } from "@/lib/sanity/image";
4. 菜单层级优化(无需useEffect)
当前代码中遮罩层已使用fixed inset-0 bg-black bg-opacity-50 z-50,只要页面其他元素的z-index不超过50,就能确保菜单显示在最上层。若需动态控制层级,可通过isMobileMenuOpen状态切换类名,现有逻辑已满足基础需求。
修改后的完整代码
/* @jsxImportSource next/client */ import { Fragment, useState } from "react"; import { Disclosure } from "@headlessui/react"; import Container from "@/components/container"; import Link from "next/link"; import Image from "next/image"; import { urlForImage } from "@/lib/sanity/image"; export default function Navbar(props) { const leftmenu = [ { label: "Home", href: "/" }, { label: "About", href: "/about" }, { label: "Contact", href: "/contact" }, { label: "Archive", href: "/archive" }, ]; const MobileMenu = () => { const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false); const handleMobileMenuToggle = () => { setIsMobileMenuOpen(!isMobileMenuOpen); }; const handleMobileMenuLinkClick = () => { setIsMobileMenuOpen(false); }; const mobilemenu = [...leftmenu]; return ( <Container> {isMobileMenuOpen && ( <div className="fixed inset-0 bg-black bg-opacity-50 z-50" onClick={handleMobileMenuToggle} /> )} <nav> <Disclosure> {({ open }) => ( <> <div className="flex flex-wrap justify-between md:flex-nowrap md:gap-10 h-24 border-b-2 border-gray-100"> <div className="flex w-full items-center justify-between"> <Link href="/" className="w-48 dark:hidden"> {props.logo ? ( <Image {...urlForImage(props.logo)} alt="Logo" priority={true} sizes="(max-width: 1040px) 100vw, 400px" /> ) : ( <span className="block text-center"> Ideato </span> )} </Link> <Link href="/" className="hidden w-48 dark:block"> {props.logoalt ? ( <Image {...urlForImage(props.logoalt)} alt="Logo" priority={true} sizes="(max-width: 1040px) 100vw, 400px" /> ) : ( <span className="block text-center"> Ideato </span> )} </Link> <Disclosure.Button aria-label="Toggle Menu" className="ml-auto pt-4 h-full rounded-md px-2 py-1 text-gray-500 focus:text-blue-500 focus:outline-none dark:text-gray-300 md:hidden " onClick={handleMobileMenuToggle} > <svg className="h-8 w-8 fill-current" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> {open && ( <path fillRule="evenodd" clipRule="evenodd" d="M18.278 16.864a1 1 0 0 1-1.414 1.414l-4.829-4.828-4.828 4.828a1 1 0 0 1-1.414-1.414l4.828-4.829-4.828-4.828a1 1 0 0 1 1.414-1.414l4.829 4.828 4.828-4.828a1 1 0 1 1 1.414 1.414l-4.828 4.829 4.828 4.828z" /> )} {!open && ( <path fillRule="evenodd" d="M4 5h16a1 1 0 0 1 0 2H4a1 1 0 1 1 0-2zm0 6h16a1 1 0 0 1 0 2H4a1 1 0 0 1 0-2zm0 6h16a1 1 0 0 1 0 2H4a1 1 0 0 1 0-2z" /> )} </svg> </Disclosure.Button> </div> <div className="order-1 hidden w-full flex-col items-center justify-start md:order-none md:flex md:w-auto md:flex-1 md:flex-row md:justify-end pt-4"> {leftmenu.map((item, index) => ( <Fragment key={`${item.label}${index}`}> {item.children && item.children.length > 0 ? ( {/* 若需要DropdownMenu,请补充组件实现 */} <div key={`${item.label}${index}`}>Dropdown Menu Placeholder</div> ) : ( <Link href={item.href} key={`${item.label}${index}`} className="px-5 py-2 text-xl font-serif font-medium text-gray-600 hover:text-blue-500 dark:text-gray-400" target={item.external ? "_blank" : ""} rel={item.external ? "noopener" : ""}> {item.label} </Link> )} </Fragment> ))} </div> </div> <Disclosure.Panel> <div className="text-xl font-serif hover:text-blue-500 dark:text-gray-400 order-2 -ml-4 mt-4 flex w-full flex-col items-center justify-start md:hidden"> {mobilemenu.map((item, index) => ( <Fragment key={`${item.label}${index}`}> {item.children && item.children.length > 0 ? ( {/* 若需要移动端DropdownMenu,请补充组件实现 */} <div key={`${item.label}${index}`}>Mobile Dropdown Menu Placeholder</div> ) : ( <Link href={item.href} key={`${item.label}${index}`} className="w-full px-5 py-2 font-medium text-gray-600 hover:text-blue-500 dark:text-gray-400" target={item.external ? "_blank" : ""} rel={item.external ? "noopener" : ""} onClick={handleMobileMenuLinkClick}> {item.label} </Link> )} </Fragment> ))} </div> </Disclosure.Panel> </> )} </Disclosure> </nav> </Container> ); } return <MobileMenu />; }
注意:原代码中引用的
DropdownMenu组件未定义,若需使用请补充实现,否则会引发新的错误,上述代码中已替换为占位符。
内容的提问来源于stack exchange,提问作者xBlady
相关产品推荐
相关产品推荐

