从React Router迁移至Next.js时Header组件渲染报错排查
Next.js Header组件渲染报错的解决方案
在Next.js App Router中将Header组件引入layout.js时出现以下报错:
Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports. Check the render method of `Header`.
核心原因
Next.js App Router的next/link组件不使用to属性(这是react-router-dom的写法),而是标准用href属性传递路径。错误的属性导致Link组件无法正确初始化,进而引发元素类型无效的报错。
修复步骤及代码优化
- 将所有
<Link>标签的to属性替换为href - 移除不必要的
Array.from(links),直接对原数组调用map方法 - 优化本地图片路径(public文件夹下的资源改用根路径
/xxx.png) - 为移动端菜单的关闭按钮补充点击事件
修改后的完整Header组件代码
"use client" import { useState } from 'react'; import Link from "next/link"; import xmark from './../../assets/xmark.svg'; import bar from './../../assets/lines.svg'; export function Header() { const links = [ { text: "Home", link: '/' }, { text: "About", link: '/about' }, { text: "Contact", link: '/contact' }, { text: "Blogs", link: "/blog_address" } ]; const linkRender = links.map((item, index) => ( <Link key={index} href={item.link} className="m-4 hover:drop-shadow-[0.2em_0.3em_5px_#000]"> {item.text} </Link> )); const small_linkRender = links.map((item, index) => ( <li key={index} id={index}> <Link href={item.link} className="m-4 hover:drop-shadow-[0.2em_0.3em_5px_#000]"> {item.text} </Link> </li> )); const [isOpen, setIsOpen] = useState(false); function grey_click(e) { const targetId = e.target.id; if (targetId === 'whitespace' || targetId === 'list_parent' || !isNaN(parseInt(targetId))) return; setIsOpen(false); } return ( <> {/* Navigation model for large devices */} <nav id='med+' className='hidden md:flex justify-between w-full h-10 bg-gray-300'> <div className='mt-auto mb-auto ml-20 flex'> <img className='mr-2' alt='Logo' src='/logo.png'></img> <span>Fatema Image Consultancy</span> </div> <div className='mt-auto mb-auto mr-20'>{linkRender}</div> </nav> {/* Navigation model for small devices */} <nav id='small' className='md:hidden flex w-full h-10 bg-gray-300'> <div></div> <div className='mt-auto ml-5 grow justify-center mb-auto flex'> <img className='mr-2' alt='Logo' src='/logo.png'></img> <span className='hidden vsm:block'>Fatema Image Consultancy</span> <span className='vsm:hidden'>Fatema Consultant</span> </div> <div className='mt-auto mb-auto mr-4'> <img src={bar} onClick={() => setIsOpen(true)} className='w-5 h-5' alt="Open menu" /> <div onClick={grey_click} className={`fixed top-0 right-0 w-screen h-screen bg-black/50 duration-500 ${isOpen ? '' : 'invisible bg-black/0'}`}> <div id="whitespace" className={`fixed right-0 top-0 ${isOpen ? '' : 'translate-x-48'} w-[10.75rem] h-screen bg-white duration-500 ease-out`}> <ul id="list_parent" className='mt-9 text-center'>{small_linkRender}</ul> <img src={xmark} onClick={() => setIsOpen(false)} className='absolute top-2 right-4 w-5 h-5 cursor-pointer' alt="Close menu" /> </div> </div> </div> </nav> </> ) }
额外说明
- Next.js App Router中,
next/link既支持默认导入也支持命名导入,两种写法均可行 - 本地静态资源建议放在
public文件夹下,使用根路径访问更可靠 - 补充关闭按钮的点击事件后,移动端菜单可以正常关闭
内容的提问来源于stack exchange,提问作者Blind Spot
相关产品推荐
相关产品推荐

