React集成Firebase Auth后刷新首页先跳转登录页再返回的问题
问题:Firebase Auth登录状态下刷新首页出现跳转闪烁
我在React应用中基于Firebase Auth实现了认证功能,设置了登录页和仅登录用户可访问的首页。但目前遇到问题:处于登录状态时刷新首页,页面会先跳转到登录页,随后又返回首页,无法排查原因。
相关代码
index.js(省略导入等内容)
root.render( <AuthProvider> <Router> <Toaster /> <AppRouter /> </Router> </AuthProvider> );
AuthProvider.js
import React, { useEffect, useState } from "react"; import { onAuthStateChanged } from "firebase/auth"; import { FirebaseAuth } from "./firebase/config"; export const AuthContext = React.createContext(); export const AuthProvider = ({ children }) => { const [currentUser, setCurrentUser] = useState(null); useEffect(() => { onAuthStateChanged(FirebaseAuth, user => { if (user) { setCurrentUser(user) } else { setCurrentUser(null) } }) }, []); return ( <AuthContext.Provider value={{ currentUser }}> {children} </AuthContext.Provider> ); };
AppRouter.js
import { useContext } from "react"; import Landing from "./screens/Landing" import { Navigate, BrowserRouter, Routes, Route } from "react-router-dom"; import Login from "./screens/auth/Login"; import { AuthContext } from './AuthProvider'; const AppRouter = () => { const { currentUser } = useContext(AuthContext); return ( <Routes> <Route path="/" element={!!currentUser ? <Landing /> : <Navigate to="/login" />} exact /> <Route path="/login" element={!currentUser ? <Login /> : <Navigate to="/" />} exact /> </Routes> ) } export default AppRouter;
问题原因
currentUser初始值为null,而Firebase的onAuthStateChanged是异步执行的。页面刷新后,AuthProvider会先以currentUser = null的状态渲染AppRouter,此时路由判断用户未登录,触发跳转到登录页;等onAuthStateChanged完成认证状态校验,拿到已登录用户信息后,currentUser更新,路由又判断用户已登录,跳回首页,最终导致页面出现跳转闪烁的现象。
解决方法
在AuthProvider中添加加载状态,标记Firebase认证状态是否初始化完成,加载期间不执行路由跳转判断:
1. 修改AuthProvider.js,添加加载状态
import React, { useEffect, useState } from "react"; import { onAuthStateChanged } from "firebase/auth"; import { FirebaseAuth } from "./firebase/config"; export const AuthContext = React.createContext(); export const AuthProvider = ({ children }) => { const [currentUser, setCurrentUser] = useState(null); // 初始化加载状态为true,表示认证状态未完成校验 const [loading, setLoading] = useState(true); useEffect(() => { // 订阅认证状态变化,并保存取消订阅函数 const unsubscribe = onAuthStateChanged(FirebaseAuth, user => { setCurrentUser(user); // 认证状态获取完成,标记加载结束 setLoading(false); }); // 组件卸载时取消订阅,避免内存泄漏 return unsubscribe; }, []); return ( <AuthContext.Provider value={{ currentUser, loading }}> {children} </AuthContext.Provider> ); };
2. 修改AppRouter.js,处理加载状态
import { useContext } from "react"; import Landing from "./screens/Landing" import { Navigate, Routes, Route } from "react-router-dom"; import Login from "./screens/auth/Login"; import { AuthContext } from './AuthProvider'; const AppRouter = () => { const { currentUser, loading } = useContext(AuthContext); // 加载期间显示加载提示,不执行路由跳转逻辑 if (loading) { return <div>加载中...</div>; // 可替换为自定义加载组件 } return ( <Routes> <Route path="/" element={!!currentUser ? <Landing /> : <Navigate to="/login" />} exact /> <Route path="/login" element={!currentUser ? <Login /> : <Navigate to="/" />} exact /> </Routes> ) } export default AppRouter;
内容的提问来源于stack exchange,提问作者crodev
相关产品推荐
相关产品推荐

