React项目中Firebase登录组件无法实现持久化认证求助
React中Firebase认证持久化失效问题排查
我正在进行React测试,想要在Login组件中实现Firebase认证持久化。我知道需要使用setPersistence,但页面刷新后认证状态无法保留。目前注册和登录功能正常,项目包含Register.jsx、Login.jsx及作为两者基础的Form.jsx组件,且使用了Redux-Toolkit,无报错信息。请问我哪里出错了?
我的base.js文件
import firebase from 'firebase/compat/app'; import { getDatabase } from 'firebase/database'; import 'firebase/compat/auth'; const firebaseConfig = { apiKey: process.env.REACT_APP_FIREBASE_API_KEY, authDomain: process.env.REACT_APP_FIREBASE_AUTH_DOMAIN, projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID, storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET, messagingSenderId: process.env.REACT_APP_FIREBASE_MESSAGING_SENDER_ID, appId: process.env.REACT_APP_FIREBASE_APP_ID, databaseURL: process.env.REACT_APP_FIREBASE_DATABASE, }; const app = firebase.initializeApp(firebaseConfig); const database = getDatabase(app); export default app;
我的Login组件
import { Form } from './Form'; import { useDispatch } from 'react-redux'; import { setUser } from '../store/slices/userSlice'; import { getAuth, setPersistence, signInWithEmailAndPassword, browserSessionPersistence, } from 'firebase/auth'; import { useNavigate } from 'react-router-dom'; const Login = () => { const dispatch = useDispatch(); const navigate = useNavigate(); const auth = getAuth(); const handleLogin = async (email, password) => { try { await setPersistence(auth, browserSessionPersistence); signInWithEmailAndPassword(auth, email, password).then(({ user }) => { console.log(user); dispatch( setUser({ email: user.email, id: user.uid, token: user.accessToken, }) ); navigate('/'); }); } catch (error) { console.error('Invalid email or password', error); } }; return <Form title='sign in' handleClick={handleLogin} />; }; export { Login };
问题原因及解决办法
1. 缺少页面初始化时的认证状态监听
Firebase会把认证信息存在浏览器缓存里,但页面刷新后,你没有主动读取这个缓存状态并同步到Redux。目前只有登录操作会触发setUser更新Redux状态,刷新后Redux状态清空,自然无法保留用户登录状态。
解决: 在根组件(比如App.jsx)中添加onAuthStateChanged监听,页面加载时自动检查用户认证状态并同步到Redux:
// App.jsx import { useEffect } from 'react'; import { getAuth, onAuthStateChanged } from 'firebase/auth'; import { useDispatch } from 'react-redux'; import { setUser } from './store/slices/userSlice'; function App() { const dispatch = useDispatch(); const auth = getAuth(); useEffect(() => { // 监听认证状态变化 const unsubscribe = onAuthStateChanged(auth, (user) => { if (user) { // 用户已登录,同步到Redux dispatch(setUser({ email: user.email, id: user.uid, token: user.accessToken })); } else { // 用户未登录,清空Redux用户状态 dispatch(setUser(null)); } }); // 组件卸载时取消监听,避免内存泄漏 return () => unsubscribe(); }, [dispatch, auth]); // ...其他组件逻辑 } export default App;
2. setPersistence调用时机不合理
你现在每次登录时都调用setPersistence,但这个配置应该在Auth实例初始化后全局设置一次,而非每次登录重复执行。
解决: 将持久化配置移到base.js中全局初始化:
// base.js 修改后 import firebase from 'firebase/compat/app'; import { getDatabase } from 'firebase/database'; import { getAuth, setPersistence, browserSessionPersistence } from 'firebase/auth'; const firebaseConfig = { // ...你的原有配置 }; const app = firebase.initializeApp(firebaseConfig); const database = getDatabase(app); const auth = getAuth(app); // 全局设置认证持久化 (async () => { try { await setPersistence(auth, browserSessionPersistence); } catch (error) { console.error('设置持久化失败:', error); } })(); export { auth, database }; export default app;
然后修改Login组件,移除重复的setPersistence调用,并使用导入的auth实例:
// Login.jsx 修改后 import { Form } from './Form'; import { useDispatch } from 'react-redux'; import { setUser } from '../store/slices/userSlice'; import { signInWithEmailAndPassword } from 'firebase/auth'; import { useNavigate } from 'react-router-dom'; import { auth } from '../base'; // 导入全局auth实例 const Login = () => { const dispatch = useDispatch(); const navigate = useNavigate(); const handleLogin = async (email, password) => { try { // 移除setPersistence调用 const { user } = await signInWithEmailAndPassword(auth, email, password); console.log(user); dispatch( setUser({ email: user.email, id: user.uid, token: user.accessToken, }) ); navigate('/'); } catch (error) { console.error('邮箱或密码错误', error); } }; return <Form title='sign in' handleClick={handleLogin} />; }; export { Login };
3. 可选优化:Redux状态持久化
如果希望Redux中的用户状态也能在页面刷新后快速恢复,可以使用redux-persist库,将用户信息存储在localStorage/sessionStorage中,避免Firebase监听的短暂延迟导致页面初始状态异常。
内容的提问来源于stack exchange,提问作者Mikhail P.
相关产品推荐
相关产品推荐

