React项目中TypeError: login is not a function错误排查求助
解决React AuthContext中TypeError: login is not a function错误
核心问题分析
你的代码存在三个关键问题导致该错误:
- useAuth钩子实现错误:当前钩子未使用React的
useContext获取上下文值,而是通过参数接收,完全违背Context的使用逻辑,导致Login组件无法拿到真正的login函数。 - App组件在AuthProvider外部调用useAuth:App是
AuthProvider的父组件,在其内部调用useAuth无法获取Context值,因为Context作用域仅覆盖Provider包裹的子组件。 - Login组件调用login时参数缺失:login函数需要
email和password两个参数,但handleSubmit中只传了email,不仅会导致后端验证失败,也是潜在的逻辑漏洞。
修复步骤
1. 修正useAuth钩子实现
修改authContext.js,让useAuth通过useContext正确获取上下文:
import React, { createContext, useState, useContext } from 'react'; import axios from 'axios'; const AuthContext = createContext(); export function AuthProvider({ children }) { const [userAuthenticated, setUserAuthenticated] = useState(false); const API = process.env.REACT_APP_API_URL; const login = async (email, password) => { try { console.log('Intentando iniciar sesión con email:', email, password); const response = await axios.post(`${API}users/login/`, { email, password }); if (response.data.isAuthenticated) { setUserAuthenticated(true); return true; } else { return false; } } catch (error) { console.error('Error en el inicio de sesión:', error); return false; } }; const logout = () => { setUserAuthenticated(false); }; return ( <AuthContext.Provider value={{ userAuthenticated, login, logout }}> {children} </AuthContext.Provider> ); } export function useAuth() { return useContext(AuthContext); }
2. 修复App组件的路由保护逻辑
创建独立的受保护路由组件,替代在App组件中直接判断用户状态:
// 新建components/ProtectedRoute.js import { Navigate } from 'react-router-dom'; import { useAuth } from './authContext'; export default function ProtectedRoute({ children }) { const { userAuthenticated } = useAuth(); return userAuthenticated ? children : <Navigate to="/login" />; }
修改App.js,移除内部的useAuth调用,改用ProtectedRoute保护/dashboard路由:
import './App.css'; import { BrowserRouter, Route, Routes } from 'react-router-dom'; import { useState, useEffect } from 'react'; import axios from 'axios'; import { AuthProvider } from './components/authContext'; import { CartProvider } from './products/cartContext'; import ProtectedRoute from './components/ProtectedRoute'; import CompShowProducts from './products/products'; import CompCreateProduct from './products/createProduct'; import CompEditProduct from './products/editProduct'; import Login from './components/login' import Header from './components/header'; import Footer from './components/footer'; import Home from './components/home'; import SearchResultPage from './components/searchResultPage'; import ProductGrid from './products/productGrid'; import MayoristaProductGrid from './products/mayProductGrid'; import ShoppingCart from './products/cart'; import AboutUs from './components/aboutUs'; import CategoryProducts from './products/categoryProducts'; import LocalLocations from './components/branches'; import ContactButton from './components/contactButton'; import GoToShopButton from './components/goToShopButton'; function App() { const [products, setProducts] = useState([]); const [brands, setBrands] = useState([]); const [categories, setCategories] = useState([]); const [searchResults, setSearchResults] = useState([]); const API = process.env.REACT_APP_API_URL; const productsAPI = `${API}products/`; axios.defaults.withCredentials = true; useEffect(() => { const fetchProducts = async () => { try { const response = await axios.get(productsAPI); setProducts(response.data); const uniqueBrands = [...new Set(response.data.map((product) => product.brand))]; setBrands(uniqueBrands); const uniqueCategories = [...new Set(response.data.map((product) => product.category.name))]; setCategories(uniqueCategories); } catch (error) { console.error('Error al obtener los datos:', error); } }; fetchProducts(); // eslint-disable-next-line }, []); return ( <AuthProvider> <CartProvider> <div className="App"> <BrowserRouter> <Header setSearchResults={setSearchResults} /> <Routes> <Route path='/' element={<Home />} /> <Route path="/productos" element={ <ProductGrid products={products} brands={brands} categories={categories} /> } /> <Route path="/mayorista" element={ <MayoristaProductGrid products={products} brands={brands} categories={categories} /> } /> <Route path='/cart' element={<ShoppingCart />} /> <Route path="/dashboard" element={ <ProtectedRoute> <CompShowProducts /> </ProtectedRoute> } /> <Route path="/create" element={<CompCreateProduct />} /> <Route path="/edit/:id" element={<CompEditProduct />} /> <Route path="/search-results" element={<SearchResultPage searchResults={searchResults} />} /> <Route path="/aboutus" element={< AboutUs />} /> <Route path="/productos/:category" element={<CategoryProducts />} /> <Route path="/sucursales" element={<LocalLocations />} /> <Route path="/login" element={<Login />} /> </Routes> <GoToShopButton/> <ContactButton/> </BrowserRouter> <Footer /> </div> </CartProvider> </AuthProvider> ); } export default App;
3. 修复Login组件的login参数传递
修改Login组件的handleSubmit,同时传入email和password:
const handleSubmit = async (e) => { e.preventDefault(); console.log('handleSubmit iniciado'); const isAuthenticated = await login(email, password); if (isAuthenticated) { console.log('Redirigiendo a /dashboard'); navigate('/dashboard'); } else { setError('Autenticación fallida'); } };
验证修复
- 重启React应用
- 尝试登录,此时login函数可正常获取Context中的实现,不会再出现
login is not a function错误 - 登录成功后会正确跳转到/dashboard,未登录时访问/dashboard会被重定向到/login
内容的提问来源于stack exchange,提问作者Dante Costamagna
相关产品推荐
相关产品推荐

