Firebase Auth onAuthStateChanged未登录即跳转问题求助
问题分析与修复方案
你遇到的未登录时自动跳转首页的问题,主要源于身份验证订阅逻辑错误、代码拼写/语法错误,以及路由跳转未做页面判断这几个点,以下是具体修复步骤和修正后的代码:
核心问题点
useEffect依赖错误:依赖userName会导致重复订阅onAuthStateChanged,且未在组件卸载时取消订阅,引发逻辑混乱- 未处理用户未登录的场景:当
user为null时未做路由控制,加上组件可能在多页面渲染,导致错误跳转 - 多处语法/拼写错误:比如
setUser = (result.user)的赋值错误、SignOut拼写错误、navigate.push使用错误、displayname属性名拼写错误
修复后的完整代码
import styled from "styled-components"; import { useDispatch, useSelector } from "react-redux"; import { useNavigate } from "react-router-dom"; import { auth, provider } from "../firebase"; import { selectUserName, selectUserPhoto, setUserLoginDetails, setSignOutState } from "../features/user/userSlice"; import { getAuth, signInWithPopup, GoogleAuthProvider, onAuthStateChanged, signOut } from "firebase/auth"; import { useEffect } from "react"; const Header = (props) => { const dispatch = useDispatch(); const navigate = useNavigate(); const userName = useSelector(selectUserName); const userPhoto = useSelector(selectUserPhoto); useEffect(() => { // 订阅身份状态变化,组件卸载时取消订阅避免内存泄漏 const unsubscribe = onAuthStateChanged(auth, (user) => { if (user) { setUser(user); // 仅当当前不在首页时才跳转,避免重复跳转 if (window.location.pathname !== "/home") { navigate("/home"); } } else { // 用户未登录时,仅当当前不在登录页时跳转 if (window.location.pathname !== "/Login") { navigate("/Login"); } dispatch(setSignOutState()); } }); return unsubscribe; }, [dispatch, navigate]); // 依赖改为稳定的dispatch和navigate const handleAuth = () => { if (!userName) { signInWithPopup(auth, provider) .then((result) => { setUser(result.user); // 修复赋值错误 }) .catch((error) => { alert(error.message); }); } else { signOut(auth) // 修复SignOut拼写错误 .then(() => { dispatch(setSignOutState()); navigate("/Login"); // 修复navigate使用方式(v6中无push方法) }) .catch((err) => alert(err.message)); } }; const setUser = (user) => { dispatch( setUserLoginDetails({ name: user.displayName, // 修复displayname拼写错误(应为displayName) email: user.email, photo: user.photoURL, }) ); }; // 补充Header的JSX渲染逻辑(原代码中缺失) return ( <StyledHeader> {/* 根据userName显示登录/退出按钮及用户信息 */} {!userName ? ( <button onClick={handleAuth}>登录</button> ) : ( <div> <img src={userPhoto} alt={userName} /> <button onClick={handleAuth}>退出</button> </div> )} </StyledHeader> ); }; // 补充styled-components定义(原代码中缺失) const StyledHeader = styled.header` // 可根据需求添加样式 `; export default Header;
额外建议
- 将身份验证的路由守卫逻辑抽离到单独组件(比如
PrivateRoute),避免在Header中处理路由跳转,让组件职责更清晰 - 确保Redux的
userSlice初始状态中userName为null或空字符串,避免初始状态判断错误
内容的提问来源于stack exchange,提问作者Kundan Agrawal
相关产品推荐
相关产品推荐

