求助:Next.js抛出WEBPACK_IMPORTED_MODULE不是函数错误的排查
问题分析与解决方案
核心问题
- Hook命名违反React规则:自定义Hook必须以
use开头,你的函数名是UseAuthUser,不符合规范,React无法正确识别这是一个Hook,会导致调用/导入异常。 - 在普通函数中调用React Hook:
getResourceMenu是普通工具函数,不是React组件或自定义Hook,违反了Hook的调用规则——Hook只能在组件顶层或其他自定义Hook顶层调用,不能在普通函数、判断、循环内执行。
修复步骤
步骤1:修正Hook命名
修改@/app/hooks/use-auth-user.ts中的函数名,改为符合规范的useAuthUser:
'use client'; import { fetchAuthSession, fetchUserAttributes, getCurrentUser, } from 'aws-amplify/auth'; import { useEffect, useState } from 'react'; // 改为以use开头的命名 export default function useAuthUser() { const [user, setUser] = useState<Record<string, any>>(); useEffect(() => { async function getUser() { const session = await fetchAuthSession(); if (!session.tokens) { return; } const user = { ...(await getCurrentUser()), ...(await fetchUserAttributes()), isAdmin: false, }; const groups = session.tokens.accessToken.payload['cognito:groups']; user.isAdmin = Boolean(groups && groups.includes('administrators')); setUser(user); } getUser(); }, []); return user; }
步骤2:调整菜单逻辑的调用位置
由于Hook不能在普通函数中调用,你需要把菜单生成逻辑移到客户端组件中:
// @/app/components/ResourceMenu.tsx 'use client'; import useAuthUser from '@/app/hooks/use-auth-user'; export default function ResourceMenu() { const user = useAuthUser(); const links = [ { name: 'Privacy Policy', href: '/privacy' }, { name: 'Terms & Conditions', href: '/terms-and-conditions' }, { name: 'Member Portal', href: '/auth/login' }, ]; if (user) { links.push({ name: 'Dashboard', href: '/dashboard' }); } return ( <nav> {links.map(link => ( <a key={link.href} href={link.href}> {link.name} </a> ))} </nav> ); }
之后在你的页面或布局组件中导入这个ResourceMenu组件即可使用,而不是调用普通函数getResourceMenu。
替代方案:封装普通异步函数获取用户
如果需要在非组件场景下获取用户信息,可以单独封装一个异步函数,再在组件中调用:
// @/app/hooks/use-auth-user.ts 'use client'; import { fetchAuthSession, fetchUserAttributes, getCurrentUser, } from 'aws-amplify/auth'; import { useEffect, useState } from 'react'; // 普通异步函数,用于获取用户信息 export async function fetchAuthUser() { const session = await fetchAuthSession(); if (!session.tokens) { return null; } const user = { ...(await getCurrentUser()), ...(await fetchUserAttributes()), isAdmin: false, }; const groups = session.tokens.accessToken.payload['cognito:groups']; user.isAdmin = Boolean(groups && groups.includes('administrators')); return user; } export default function useAuthUser() { const [user, setUser] = useState<Record<string, any>>(); useEffect(() => { fetchAuthUser().then(setUser); }, []); return user; }
然后在组件中通过useEffect调用这个函数生成菜单:
'use client'; import { fetchAuthUser } from '@/app/hooks/use-auth-user'; import { useState, useEffect } from 'react'; export default function SomeComponent() { const [links, setLinks] = useState([ { name: 'Privacy Policy', href: '/privacy' }, { name: 'Terms & Conditions', href: '/terms-and-conditions' }, { name: 'Member Portal', href: '/auth/login' }, ]); useEffect(() => { async function loadMenu() { const user = await fetchAuthUser(); if (user) { setLinks(prev => [...prev, { name: 'Dashboard', href: '/dashboard' }]); } } loadMenu(); }, []); return ( <nav> {links.map(link => ( <a key={link.href} href={link.href}>{link.name}</a> ))} </nav> ); }
内容的提问来源于stack exchange,提问作者FevtheDev
相关产品推荐
相关产品推荐

