React Context封装的login函数调用报错,疑为语法问题求助
问题排查:React Context封装Firebase登录函数报错
问题现象
- 调用React Context提供的
login函数时,抛出错误:Firebase: Error (auth/invalid-value-(email),-starting-an-object-on-a-scalar-field) - 直接调用Firebase原生
signInWithEmailAndPassword函数则正常工作,且两种调用的参数完全一致
错误原因
核心问题是参数不匹配:
Context中的login函数内部已经封装了全局auth实例,仅需传入email和password两个参数;但调用时额外传入了auth对象,导致Firebase把auth对象当作email参数处理——而email要求是字符串(标量值),传入对象直接触发了类型错误。
修复方案
1. 修正Login.tsx中的函数调用
移除多余的auth参数,只传入email和password:
// Login.tsx 修正后代码 import { useAuth } from '../../config/AuthContext'; import { useRouter } from 'next/router'; export function AuthenticationForm(props: PaperProps) { const { login } = useAuth(); const router = useRouter(); const handleLogin = async (data: LoginType) => { try { await login(data.email, data.password); // 移除多余的auth参数 router.push("/Dashboard"); } catch (error: any) { console.log(error.message); } }; return ( // ... 表单代码 <form onSubmit={form.onSubmit(handleLogin)}> {/* ... 表单元素 */} </form> ); }
2. 补全AuthContext中的缺失函数
原代码中AuthContext.Provider的value包含logout,但未定义该函数,需要补上:
// AuthContext.tsx 中添加logout函数 const logout = () => { return signOut(auth); };
3. 优化Context类型定义(可选)
为避免后续类型不匹配问题,给Context添加明确的类型约束,替换any类型:
// AuthContext.tsx 完整修正代码 import React, { createContext, useContext, useEffect, useState } from "react"; import { onAuthStateChanged, createUserWithEmailAndPassword, signInWithEmailAndPassword, signOut, } from "firebase/auth"; import { auth } from "./firebase"; interface UserType { email: string | null; uid: string | null; } interface AuthContextType { user: UserType; register: (email: string, password: string) => Promise<any>; login: (email: string, password: string) => Promise<any>; logout: () => Promise<void>; } const AuthContext = createContext<AuthContextType>({ user: { email: null, uid: null }, register: async () => {}, login: async () => {}, logout: async () => {}, }); export const useAuth = () => useContext(AuthContext); export const AuthContextProvider = ({ children }: { children: React.ReactNode }) => { const [user, setUser] = useState<UserType>({ email: null, uid: null }); const [loading, setLoading] = useState<boolean>(true); useEffect(() => { const unsubscribe = onAuthStateChanged(auth, (user) => { if (user) { setUser({ email: user.email, uid: user.uid }); } else { setUser({ email: null, uid: null }); } setLoading(false); // 将setLoading移到回调内,确保监听完成后再渲染子组件 }); return () => unsubscribe(); }, []); const register = (email: string, password: string) => { return createUserWithEmailAndPassword(auth, email, password); }; const login = (email: string, password: string) => { return signInWithEmailAndPassword(auth, email, password); }; const logout = () => { return signOut(auth); }; return ( <AuthContext.Provider value={{ user, register, login, logout }}> {loading ? null : children} </AuthContext.Provider> ); };
4. 修正_app.tsx的语法错误
原代码中return语句前多了多余的分号,修正后:
// _app.tsx 修正后代码 import { AuthContextProvider } from "../config/AuthContext"; import Head from "next/head"; import { NotificationsProvider } from "你的通知库路径"; export default function App(props: AppProps & { colorScheme: ColorScheme }) { const { Component, pageProps } = props; return ( <AuthContextProvider> <Head> <title>Awesome App</title> </Head> <NotificationsProvider> <Component {...pageProps} /> </NotificationsProvider> </AuthContextProvider> ); } App.getInitialProps = async (appContext: AppContext) => { const appProps = await NextApp.getInitialProps(appContext); return { ...appProps }; };
内容的提问来源于stack exchange,提问作者Lewis
相关产品推荐
相关产品推荐

