You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NextJS 13.0.6+TypeScript+Firebase中AuthContext未捕获TypeError

问题:Next.js 13 + TypeScript 中使用 AuthContext 时出现 useUserAuth is not a function 错误

我想实现用户登录后才显示页面的功能,当前应用只有 AuthContext 和目标页面,代码在 React 中能正常运行,但迁移到 TypeScript 和 Next.js 13 后报错,我对这两者都不熟悉,求帮忙解决。


AuthContext.tsx

'use client';
import { useContext, createContext, useEffect, useState } from 'react';
import {
  GoogleAuthProvider,
  signInWithPopup,
  signInWithRedirect,
  signOut,
  onAuthStateChanged,
  signInWithEmailAndPassword,
  User,
} from 'firebase/auth';
import { auth } from '../../../firebaseConfig';
import getUserData from '../api/getUserData';

//-----------------------interfaces-----------------------------------------

interface Props {
  children: React.ReactNode;
}

interface SignInCredentials {
  email: string;
  password: string;
}

export interface AuthContextValues {
  googleSignIn: () => void;
  emailSignIn: ({ email, password }: SignInCredentials) => void;
  logout: () => void;
  user: User | null;
  userProfileData: any;
  loadingUser: boolean;
}

//-----------------AuthContextProvider--------------------------------------
const emailSignIn = ({ email, password }: SignInCredentials) => {
  try {
    signInWithEmailAndPassword(auth, email, password);
  } catch (e) {
    console.error(e);
  }
};
const googleSignIn = () => {
  const provider = new GoogleAuthProvider();
  signInWithRedirect(auth, provider);
};

const initialState: AuthContextValues = {
  user: null,
  googleSignIn,
  emailSignIn,
  logout: function (): void {
    throw new Error('Function not implemented.');
  },
  userProfileData: undefined,
  loadingUser: false,
};

const AuthContext = createContext<AuthContextValues>(initialState);

export const AuthContextProvider = ({ children }: Props) => {
  const [user, setUser] = useState<User | null>(null);
  const [userProfileData, setUserProfileData] = useState(null); 
  const [loadingUser, setLoadingUser] = useState<boolean>(true);

  const logout = async () => {
    await signOut(auth);
    setUser(null);
    setUserProfileData(null);
  };

  useEffect(() => {
    const unsubscribe = onAuthStateChanged(auth, async (currentUser) => {
      try {
        if (currentUser) {
          setUser(currentUser);
          await getUserData(currentUser, setUserProfileData);
        } else {
          setUser(null);
          console.log('no user detected in onAuthStateChanged');
        }
      } catch (e) {
        console.error(e);
        // toast.error('There was a problem signing in. Please try again.')
      } finally {
        setLoadingUser(false);
      }
    });
    return () => {
      unsubscribe();
    };
  }, []);

  console.log(user);
  console.log(userProfileData);

  return (
    <AuthContext.Provider
      value={{
        googleSignIn,
        emailSignIn,
        logout,
        user,
        userProfileData,
        loadingUser,
      }}
    >
      {children}
    </AuthContext.Provider>
  );
};

export const useUserAuth = () => {
  return useContext(AuthContext);
};

page.tsx(用户页面)

import React from 'react';
import { useUserAuth } from './../../components/shared/context/AuthContext';

type Props = {};

export default function UserPage(props: Props) {
  const { user } = useUserAuth();
  return <> {user?.uid} </>;
}

layout.tsx(根布局)

import './global.css';
import { AuthContextProvider } from './../components/shared/context/AuthContext';

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang='en'>
      <body>
        <AuthContextProvider>{children}</AuthContextProvider>
      </body>
    </html>
  );
}

错误信息

client.js?234c:691 Uncaught TypeError: (0 , _components_shared_context_AuthContext__WEBPACK_IMPORTED_MODULE_2__.useUserAuth) is not a function
    at UserPage (webpack-internal:///(sc_server)/./app/user/page.tsx:13:106)
    at attemptResolveElement (webpack-internal:///(sc_server)/./node_modules/next/dist/compiled/react-server-dom-webpack/server.browser.js:1207:42)
    at resolveModelToJSON (webpack-internal:///(sc_server)/./node_modules/next/dist/compiled/react-server-dom-webpack/server.browser.js:1660:53)
    at Array.toJSON (webpack-internal:///(sc_server)/./node_modules/next/dist/compiled/react-server-dom-webpack/server.browser.js:1121:40)
    at stringify (<anonymous>)
    at processModelChunk (webpack-internal:///(sc_server)/./node_modules/next/dist/compiled/react-server-dom-webpack/server.browser.js:172:36)
    at retryTask (webpack-internal:///(sc_server)/./node_modules/next/dist/compiled/react-server-dom-webpack/server.browser.js:1868:50)
    at performWork (webpack-internal:///(sc_server)/./node_modules/next/dist/compiled/react-server-dom-webpack/server.browser.js:1906:33)
    at eval (webpack-internal:///(sc_server)/./node_modules/next/dist/compiled/react-server-dom-webpack/server.browser.js:1297:40)
    at scheduleWork (webpack-internal:///(sc_server)/./node_modules/next/dist/compiled/react-server-dom-webpack/server.browser.js:52:25)
    at pingTask (webpack-internal:///(sc_server)/./node_modules/next/dist/compiled/react-server-dom-webpack/server.browser.js:1296:29)
    at ping (webpack-internal:///(sc_server)/./node_modules/next/dist/compiled/react-server-dom-webpack/server.browser.js:1309:40)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
resolveErrorDev @   client.js?234c:691
processFullRow  @   client.js?234c:756
processBinaryChunk  @   client.js?234c:789
progress    @   client.js?234c:842

已尝试的方法

  • 重命名 useUserAuth,无效
  • 原无 TypeScript 的代码在 React 18 中正常运行

解决方法

这个错误的核心原因是 Next.js 13 的 App Router 默认采用 Server Components,而你在 Server Component 中调用了只能在 Client Component 中使用的自定义 Hook(useUserAuth 依赖 React Context,属于 Client 侧 API)。

步骤1:将用户页面标记为 Client Component

在 page.tsx 顶部添加 'use client'; 指令,告诉 Next.js 这个组件需要在客户端运行:

'use client'; // 新增这一行
import React from 'react';
import { useUserAuth } from './../../components/shared/context/AuthContext';

type Props = {};

export default function UserPage(props: Props) {
  const { user } = useUserAuth();
  return <> {user?.uid} </>;
}

步骤2:优化 AuthContext 的类型定义(可选但推荐)

当前 userProfileData 的类型是 any,可以换成更明确的类型来发挥 TypeScript 的优势。比如先定义一个用户数据接口:

// 在 AuthContext.tsx 中新增
interface UserProfileData {
  // 根据你的实际数据结构定义字段,比如:
  id: string;
  name: string;
  // ...其他字段
}

// 然后修改 AuthContextValues 和 useState 的类型
export interface AuthContextValues {
  // ...其他字段
  userProfileData: UserProfileData | null; // 替换 any
}

// 在 AuthContextProvider 中
const [userProfileData, setUserProfileData] = useState<UserProfileData | null>(null);

步骤3:处理 loading 状态(可选)

当前页面在用户加载完成前会直接显示 undefined,可以利用 loadingUser 状态添加加载提示:

// 修改 UserPage
export default function UserPage(props: Props) {
  const { user, loadingUser } = useUserAuth();
  
  if (loadingUser) {
    return <div>加载中...</div>;
  }

  if (!user) {
    // 若用户未登录,可以跳转到登录页或显示提示
    return <div>请先登录</div>;
  }

  return <> {user.uid} </>;
}

内容的提问来源于stack exchange,提问作者Tom Ash

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 07:20:38