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

React+TypeScript登录调用auth.signin报undefined属性读取错误

报错现象

开发React+TypeScript项目时触发固定报错:Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'signin')

  • 触发场景:登录页执行登录处理函数时抛出,表单内输入的邮箱、密码值均正确
  • 报错位置参考:报错位置截图
问题根因
  • 核心原因:Login组件未被AuthProvider包裹,调用useContext(AuthContext)获取到的上下文值为undefined,尝试读取undefined上的signin方法直接触发类型错误。
  • 类型隐患:调用createContext创建上下文时未传入默认值,TypeScript未在编译阶段提前识别到上下文可能为undefined的风险,问题直接暴露在运行时。
  • 代码疏漏:
    • AuthProvider向上下文传递的value包含signout字段,但组件内部未实现该方法,后续调用时会触发同类错误
    • 贴出的Login、AuthProvider代码中使用了useState、useContext、ChangeEvent等React API,但未从react包显式导入,运行时会触发未定义错误
修复方案

按以下步骤修改即可正常运行:

  1. 调整根组件/路由配置,确保所有需要使用鉴权上下文的组件都被AuthProvider包裹
    示例正确配置(以App.tsx为例):
    import { BrowserRouter, Routes, Route } from 'react-router-dom';
    import { AuthProvider } from './contexts/Auth/AuthProvider';
    import { Login } from './pages/Login';
    import Dashboard from './pages/Dashboard';
    
    function App() {
      return (
        <BrowserRouter>
          <AuthProvider>
            <Routes>
              <Route path="/login" element={<Login />} />
              <Route path="/dashboard" element={<Dashboard />} />
            </Routes>
          </AuthProvider>
        </BrowserRouter>
      )
    }
    
  2. 优化上下文定义,增加类型校验
    修改AuthContext定义代码,传入默认值避免运行时取值为undefined:
    import { createContext } from "react";
    import { User } from "../../types/User";
    
    export type AuthContextType = {
      user: User | null;
      signin: (email: string, password: string) => Promise<boolean>;
      signout: () => void;
    };
    
    export const AuthContext = createContext<AuthContextType>({} as AuthContextType);
    
    可选严谨优化:封装自定义useAuth hook,当组件未在Provider内使用时抛出明确错误:
    import { useContext } from "react";
    import { AuthContext, AuthContextType } from "./AuthContext";
    
    export const useAuth = (): AuthContextType => {
      const context = useContext(AuthContext);
      if (!context) throw new Error("useAuth 必须在 AuthProvider 内部使用");
      return context;
    }
    
    后续组件中直接调用const auth = useAuth()即可,不用重复做非空判断。
  3. 补全缺失的代码逻辑和导入
    • 补全AuthProvider中的signout方法,补全React API导入:
    import { useState } from "react";
    import { useApi } from "../../hooks/useApi";
    import { User } from "../../types/User";
    import { AuthContext } from "./AuthContext";
    
    export const AuthProvider = ({ children }: { children: JSX.Element }) => {
      const [user, setUser] = useState<User | null>(null);
      const api = useApi();
    
      const signin = async (email: string, password: string) => {
        const data = await api.signin(email, password);
        if (data.user && data.token) {
          setUser(data.user);
          setToken(data.token);
          return true;
        }
        return false;
      };
    
      // 补全signout实现
      const signout = () => {
        setUser(null);
        localStorage.removeItem("authToken");
      };
    
      const setToken = (token: string) => {
        localStorage.setItem("authToken", token);
      };
    
      return (
        <AuthContext.Provider value={{ user, signin, signout }}>
          {children}
        </AuthContext.Provider>
      );
    };
    
    • 补全Login组件中缺失的React API导入:
    import { useState, ChangeEvent, useContext } from "react";
    import { Link, useNavigate } from "react-router-dom";
    import { At, LockLaminated } from "phosphor-react";
    import { AuthContext } from "../contexts/Auth/AuthContext";
    // 使用自定义useAuth时替换上面的导入为 import { useAuth } from "../contexts/Auth/useAuth";
    import { Loading } from "../components/Loading";
    import favicon from "../assets/favicon.ico";
    
    export const Login = () => {
      const auth = useContext(AuthContext);
      // 使用自定义useAuth时替换为 const auth = useAuth();
      const navigate = useNavigate();
      // 其余原有逻辑保持不变
    

内容的提问来源于stack exchange,提问作者Pedro Beck

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 16:09:22