如何在React应用中通过Firebase Auth实现强制登录并解决登录跳转异常问题
问题根因
- 登录成功后无跳转逻辑:Signin组件的登录/注册成功回调中仅打印了日志,未调用React Router的跳转方法
- 缺少路由访问控制:未做登录状态校验,未登录用户可直接访问内部业务页面
- 路由结构不符合需求:修改后的App.js将Sidebar单独设置为路由页,实际需要的是所有内部业务页面都共用侧边栏导航
代码修改方案
1. 修改Signin.js 增加登录成功跳转逻辑
import React, { useRef } from 'react' import { useNavigate } from 'react-router' // 新增引入跳转钩子 import firebaseObj from '../firebase/firebase' const auth = firebaseObj.auth const Signin = () => { const navigate = useNavigate() // 初始化跳转方法 const emailRef = useRef(null); const passwordRef = useRef(null); const signUp = e => { e.preventDefault(); auth.createUserWithEmailAndPassword( emailRef.current.value, passwordRef.current.value ).then(user => { console.log(user) navigate('/ordenes') // 注册成功跳转到订单页 }).catch(err => { console.log(err) }) } const signIn = e => { e.preventDefault(); auth.signInWithEmailAndPassword( emailRef.current.value, passwordRef.current.value ).then(user => { console.log(user) navigate('/ordenes') // 登录成功跳转到订单页 }).catch(err => { console.log(err) }) } return ( <div className="mb-4"> <form action=""> <h1>Sign in</h1> <input className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" ref={emailRef} type="email" placeholder="email"/> <input className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" ref={passwordRef} type="password" /> <button onClick={signIn}>Sign in </button> </form> </div> ) } export default Signin
2. 修改App.js 增加路由守卫+调整路由结构
import React, { useState, useEffect } from 'react' import { Routes, Route, Navigate } from 'react-router' // 新增引入重定向组件 import firebase, { FirebaseContext } from './firebase' import firebaseObj from './firebase' import Ordenes from './components/paginas/Ordenes' import Menu from './components/paginas/Menu' import NuevoPlato from './components/paginas/NuevoPlato' import Sidebar from './components/ui/Sidebar' import Signin from './components/Signin' const auth = firebaseObj.auth function App() { const [user, setUser] = useState(null) const [loading, setLoading] = useState(true) // 新增加载状态,避免登录状态未初始化时跳转错误 useEffect(() => { const unsubscribe = auth.onAuthStateChanged(userAuth => { const user = { uid: userAuth?.uid, email: userAuth?.email } if (userAuth) { console.log(userAuth) setUser(user) } else { setUser(null) } setLoading(false) // 状态初始化完成,关闭加载 }) return unsubscribe }, []) // 加载中可自定义加载动画,这里做简化处理 if(loading) return <div>加载中...</div> return ( <FirebaseContext.Provider value={{ firebase }} > <div className="md:flex min-h-screen" > {/* 已登录才显示侧边栏 */} {user && <Sidebar />} <div className="md:w-2/5 xl:w-4/5 p-6"> <Routes> {/* 未登录可访问登录页,已登录访问登录页自动跳转到订单页 */} <Route path="/" element={user ? <Navigate to="/ordenes" /> : <Signin />} /> {/* 内部路由:未登录访问自动跳转到登录页 */} <Route path="/ordenes" element={user ? <Ordenes /> : <Navigate to="/" />} /> <Route path="/menu" element={user ? <Menu /> : <Navigate to="/" />} /> <Route path="/nuevo-plato" element={user ? <NuevoPlato /> : <Navigate to="/" />} /> </Routes> </div> </div> </FirebaseContext.Provider> ) } export default App
注意事项
- 请确认你的项目已正确安装
react-router-dom依赖,若未安装可执行npm i react-router-dom完成安装 - 注意之前代码中
NuevoPlato和NuevoProducto的命名不一致问题,按实际组件名调整即可
内容的提问来源于stack exchange,提问作者Miguel Espeso
相关产品推荐
相关产品推荐

