React Router中NavLink点击后URL变化但页面不加载问题求助
问题描述
构建了一个多页面React应用,导航栏包含“Login”“Signup”等认证相关NavLink。手动输入URL时页面可正常加载对应内容,但点击同URL的NavLink时,仅URL变化而页面不加载,甚至进入循环状态,需停止本地服务器并关闭标签页才能终止。
依赖版本:
react: ^18.2.0react-router-dom: ^6.6.2
附相关代码:
App.js
import { BrowserRouter, Routes, Route, Navigate } from "react-router-dom"; import Navigation from "./components/Navigation"; import LogIn from "./pages/LogIn"; import Home from "./pages/Home"; // 补充原代码缺失的导入 import SignUp from "./pages/SignUp"; // 补充原代码缺失的导入 function App() { return ( <> <BrowserRouter> <Navigation /> <Routes> <Route index element={<Home />} /> <Route path="/login" element={<LogIn />} /> <Route path="/signup" element={<SignUp />} /> </Routes> </BrowserRouter> </> ); } export default App;
Navigation.jsx
import { auth } from "../firebase"; import { signOut, onAuthStateChanged } from "firebase/auth"; import { toast } from "react-toastify"; import { NavLink, useNavigate } from "react-router-dom"; import { useState } from "react"; export default function Navigation() { const user = auth.currentUser; const [isLoggedIn, setIsLoggedIn] = useState(); onAuthStateChanged(auth, (user) => { if (user) { setIsLoggedIn(true); } else { setIsLoggedIn(false); } }); const navigate = useNavigate(); const onLogOut = () => { signOut(auth) .then(() => { toast.success("You are signed out"); console.log("You are signed out"); navigate("/login"); }) .catch((error) => { toast.error("Something went wrong"); console.log(error.message); }); }; return ( <> <ul className="flex p-2 place-content-evenly"> <li>BraThula</li> {!isLoggedIn && <NavLink to="login">Login</NavLink>} {!isLoggedIn && <NavLink to="signup">Signup</NavLink>} {isLoggedIn && ( <li className="cursor-pointer" onClick={onLogOut}> logout </li> )} {isLoggedIn && <li className="">Hello, {user.name}</li>} {isLoggedIn && <li className="">Current User: {user.email}</li>} </ul> </> ); }
问题根源与修复方案
核心问题
onAuthStateChanged监听未清理:在组件顶层直接调用onAuthStateChanged,每次组件渲染都会新增一个监听回调,导致回调堆积。用户状态变化时,多个回调触发setIsLoggedIn,引发组件反复渲染,最终形成循环。- 用户信息读取错误:直接读取
auth.currentUser无法实时同步用户状态,且Firebase用户的名称字段是displayName而非name,原代码存在字段错误。 - 相对路径跳转隐患:
NavLink使用to="login"相对路径,在非根路径下可能导致跳转异常。
修复步骤
1. 用useEffect包裹监听并添加清理逻辑
通过useEffect注册监听,返回清理函数移除监听,避免回调堆积:
import { useEffect, useState } from "react"; export default function Navigation() { const [isLoggedIn, setIsLoggedIn] = useState(false); const [user, setUser] = useState(null); // 用state存储实时用户信息 useEffect(() => { const unsubscribe = onAuthStateChanged(auth, (user) => { if (user) { setIsLoggedIn(true); setUser(user); } else { setIsLoggedIn(false); setUser(null); } }); // 组件卸载时清理监听 return unsubscribe; }, []); // 空依赖数组确保监听只注册一次
2. 修正用户信息读取逻辑
使用state中存储的user对象,同时修正Firebase用户名称字段:
// 原错误代码 {isLoggedIn && <li className="">Hello, {user.name}</li>} // 修正后 {isLoggedIn && <li className="">Hello, {user.displayName}</li>}
3. 统一使用绝对路径跳转
将NavLink的to属性改为绝对路径,避免相对路径跳转异常:
{!isLoggedIn && <NavLink to="/login">Login</NavLink>} {!isLoggedIn && <NavLink to="/signup">Signup</NavLink>}
完整修复后的Navigation.jsx
import { auth } from "../firebase"; import { signOut, onAuthStateChanged } from "firebase/auth"; import { toast } from "react-toastify"; import { NavLink, useNavigate } from "react-router-dom"; import { useState, useEffect } from "react"; export default function Navigation() { const [isLoggedIn, setIsLoggedIn] = useState(false); const [user, setUser] = useState(null); const navigate = useNavigate(); useEffect(() => { const unsubscribe = onAuthStateChanged(auth, (user) => { if (user) { setIsLoggedIn(true); setUser(user); } else { setIsLoggedIn(false); setUser(null); } }); return unsubscribe; }, []); const onLogOut = () => { signOut(auth) .then(() => { toast.success("You are signed out"); console.log("You are signed out"); navigate("/login"); }) .catch((error) => { toast.error("Something went wrong"); console.log(error.message); }); }; return ( <> <ul className="flex p-2 place-content-evenly"> <li>BraThula</li> {!isLoggedIn && <NavLink to="/login">Login</NavLink>} {!isLoggedIn && <NavLink to="/signup">Signup</NavLink>} {isLoggedIn && ( <li className="cursor-pointer" onClick={onLogOut}> logout </li> )} {isLoggedIn && <li className="">Hello, {user.displayName}</li>} {isLoggedIn && <li className="">Current User: {user.email}</li>} </ul> </> ); }
内容的提问来源于stack exchange,提问作者Coolkid
相关产品推荐
相关产品推荐

