Next.js 14中无法使用ShadcnUI Navigation Menu的问题排查
问题场景
在Next.js 14的Header组件中使用ShadcnUI的Navigation Menu组件,直接采用官方示例代码后出现错误,移除该组件后Header恢复正常工作。
Header组件代码:
import {auth} from '@/auth' import { NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, } from "@/components/ui/navigation-menu" const Header = async () => { const session = await auth() let authContent : React.ReactNode; if (session?.user) { authContent = <div className="avatar placeholder"> <div className="bg-neutral text-neutral-content rounded-full w-25"> </div> </div> } else { authContent = <ul className="p-2"> <li><a>Login</a></li> <li><a>Register</a></li> </ul> } return ( <NavigationMenu> <NavigationMenuList> <NavigationMenuItem> <NavigationMenuTrigger>Item One</NavigationMenuTrigger> <NavigationMenuContent> <NavigationMenuLink>Link</NavigationMenuLink> </NavigationMenuContent> </NavigationMenuItem> </NavigationMenuList> </NavigationMenu> ); } export default Header;
报错信息
TypeError: (0 , react__WEBPACK_IMPORTED_MODULE_0__.createContext) is not a function at eval (webpack-internal:///(rsc)/./node_modules/@radix-ui/react-direction/dist/index.mjs:11:114) at (rsc)/./node_modules/@radix-ui/react-direction/dist/index.mjs (/home/me/dev/discuss/.next/server/vendor-chunks/@radix-ui.js:60:1) at __webpack_require__ (/home/me/dev/discuss/.next/server/webpack-runtime.js:33:42) at eval (webpack-internal:///(rsc)/./node_modules/@radix-ui/react-navigation-menu/dist/index.mjs:31:83) at (rsc)/./node_modules/@radix-ui/react-navigation-menu/dist/index.mjs (/home/me/dev/discuss/.next/server/vendor-chunks/@radix-ui.js:90:1) at __webpack_require__ (/home/me/dev/discuss/.next/server/webpack-runtime.js:33:42) at eval (webpack-internal:///(rsc)/./src/components/ui/navigation-menu.tsx:17:89) at (rsc)/./src/components/ui/navigation-menu.tsx (/home/me/dev/discuss/.next/server/app/page.js:443:1) at __webpack_require__ (/home/me/dev/discuss/.next/server/webpack-runtime.js:33:42) at eval (webpack-internal:///(rsc)/./src/components/header.tsx:8:88) at (rsc)/./src/components/header.tsx (/home/me/dev/discuss/.next/server/app/page.js:403:1) at __webpack_require__ (/home/me/dev/discuss/.next/server/webpack-runtime.js:33:42) at eval (webpack-internal:///(rsc)/./src/app/layout.tsx:12:76) at (rsc)/./src/app/layout.tsx (/home/me/dev/discuss/.next/server/app/page.js:359:1) at Function.__webpack_require__ (/home/me/dev/discuss/.next/server/webpack-runtime.js:33:42) at async e9 (/home/me/dev/discuss/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:35:396515) at async tb (/home/me/dev/discuss/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:35:400212) at async tS (/home/me/dev/discuss/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:35:400773) at async tR (/home/me/dev/discuss/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:36:2130) at async /home/me/dev/discuss/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:36:2722 { digest: '717147068', page: '/' } ○ Compiling /_error ...
项目依赖配置
"dependencies": { "@auth/core": "^0.18.1", "@auth/prisma-adapter": "^2.1.0", "@prisma/client": "^5.14.0", "@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-navigation-menu": "^1.1.4", "@radix-ui/react-slot": "^1.0.2", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "lucide-react": "^0.379.0", "next": "^14.2.3", "next-auth": "^5.0.0-beta.3", "prisma": "^5.14.0", "radix-ui": "^1.0.1", "react": "^18", "react-dom": "^18", "tailwind-merge": "^2.3.0", "tailwindcss-animate": "^1.0.7" }, "devDependencies": { "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", "autoprefixer": "^10.0.1", "postcss": "^8", "tailwindcss": "^3.4.3", "typescript": "^5" }
问题根源
Header组件是服务器组件(RSC),而ShadcnUI的Navigation Menu依赖Radix UI的客户端组件,这类组件需要使用React Context(createContext),但服务器组件环境中不支持React的客户端API,因此抛出该错误。
解决方法
方法1:将Header转为客户端组件
在Header组件顶部添加'use client'指令,标记该组件为客户端组件,即可使用需要Context的交互UI:
'use client' // 新增该行 import {auth} from '@/auth' // 其余导入和代码保持不变 const Header = async () => { // 原逻辑不变 }
注:添加'use client'后,组件仍可保持异步,正常调用auth()获取会话信息。
方法2:拆分组件,单独封装客户端导航菜单
若不想将整个Header转为客户端组件,可把Navigation Menu部分抽成独立的客户端组件:
- 创建
components/ui/NavigationMenuClient.tsx:
'use client' import { NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, } from "@/components/ui/navigation-menu" export default function NavigationMenuClient() { return ( <NavigationMenu> <NavigationMenuList> <NavigationMenuItem> <NavigationMenuTrigger>Item One</NavigationMenuTrigger> <NavigationMenuContent> <NavigationMenuLink>Link</NavigationMenuLink> </NavigationMenuContent> </NavigationMenuItem> </NavigationMenuList> </NavigationMenu> ) }
- 在原Header组件中导入使用:
import {auth} from '@/auth' import NavigationMenuClient from '@/components/ui/NavigationMenuClient' const Header = async () => { const session = await auth() // 原authContent逻辑不变 return ( <> {/* 原Header其他内容 */} <NavigationMenuClient /> </> ) }
额外优化建议
- 卸载多余依赖:
package.json中的radix-ui包是冗余的,已安装具体的Radix UI组件包(如@radix-ui/react-navigation-menu),可执行npm uninstall radix-ui移除。 - 版本兼容性:当前使用的
@radix-ui/react-navigation-menu@1.1.4与Next.js 14兼容,无需调整版本。
内容的提问来源于stack exchange,提问作者blnks
相关产品推荐
相关产品推荐

