Next.js登录后无法自动渲染Profile与Logout按钮问题求助
问题解决:登录后需刷新才显示Profile/Logout按钮
你创建了检查Cookie中token的API,登出时导航栏能自动切换状态,但登录后必须刷新页面才会显示Profile和Logout按钮。
问题原因
当前代码中grabEmail仅在Header组件首次挂载时执行一次(空依赖数组的useEffect)。登录操作完成后,Header组件没有重新触发登录状态检查,因此isLoggedIn状态保持初始的false,直到页面刷新重新挂载组件才会更新。
方案1:利用已导入的Auth Context(推荐)
你已经导入了useAuth,说明项目存在全局认证状态管理。直接使用Context中的登录状态代替本地isLoggedIn,登录成功后Context更新时,Header会自动重新渲染。
修改后的代码示例:
import React, { useState } from 'react'; import { useAuth } from '@/app/authContext'; import { useRouter } from 'next/navigation'; import Link from 'next/link'; import axios from 'axios'; export default function Header() { const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false); const [showModal, setShowModal] = useState(false); const { isLoggedIn, logout } = useAuth(); // 从Auth Context获取状态和登出方法 const router = useRouter(); const toggleMobileMenu = () => { setIsMobileMenuOpen(!isMobileMenuOpen); }; const handleMenuItemClick = () => { setIsMobileMenuOpen(false); }; const handleLogout = () => { setShowModal(true); }; const confirmLogout = async () => { try { await axios.get('/api/users/logout'); logout(); // 调用Auth Context的登出方法更新全局状态 setIsMobileMenuOpen(false); router.push('/'); setShowModal(false); } catch (error) { console.error("Error logging out:", error); } }; const closeModal = () => { setShowModal(false); }; // 其余return部分代码保持不变 return ( <header className='bg-white border-b flex justify-between p-4'> <div className="flex items-center gap-6"> <Link href={'/'}>FashionFinder </Link> <nav className='hidden md:flex gap-4'> <Link href={'/about'}>About</Link> <Link href={'/contact'}>Contact Us</Link> <Link href={'/albums'}>Albums</Link> </nav> </div> <div className="relative md:hidden"> <button id="menu-toggle" className="outline-none focus:outline-none" onClick={toggleMobileMenu} > <svg className="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" > <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M4 6h16M4 12h16M4 18h16" ></path> </svg> </button> {isMobileMenuOpen && ( <div className="fixed inset-0 bg-gray-700 bg-opacity-50 overflow-y-auto z-50"> <div className="fixed top-0 right-0 w-1/2 h-screen bg-gray-800 flex flex-col items-center justify-center overflow-y-auto"> <button className="absolute top-4 left-4 outline-none focus:outline-none" onClick={toggleMobileMenu} > <svg className="w-6 h-6 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor" > <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12" /> </svg> </button> <nav className="flex flex-col items-center gap-4 text-white"> <Link href="/about" onClick={handleMenuItemClick}>About</Link> <Link href="/contact" onClick={handleMenuItemClick}>Contact</Link> <Link href="/albums" onClick={handleMenuItemClick}>Albums</Link> {isLoggedIn ? ( <> <Link href="/profile" onClick={handleMenuItemClick}>Profile</Link> <button onClick={handleLogout} className="text-white" > Logout </button> </> ) : ( <> <Link href="/login" onClick={handleMenuItemClick}>Sign In</Link> <Link href="/register" onClick={handleMenuItemClick}>Create Account</Link> </> )} </nav> </div> </div> )} </div> {/* Full-screen logout modal */} {showModal && ( <div className="fixed inset-0 flex items-center justify-center z-50 bg-gray-700 bg-opacity-50"> <div className="bg-white p-10 rounded-md shadow-lg"> <h2 className="text-lg font-semibold mb-4">Are you sure you want to logout?</h2> <div className="flex items-center justify-center"> <button className="bg-black text-white px-4 py-2 rounded-md mr-2 font-semibold" onClick={confirmLogout} > Yes </button> <button className="bg-gray-300 text-gray-800 px-4 py-2 rounded-md font-semibold" onClick={closeModal} > No </button> </div> </div> </div> )} <nav className='hidden md:flex items-center gap-4'> {isLoggedIn ? ( <> <Link href={'/profile'}>Profile</Link> <button onClick={handleLogout} className="bg-black text-white px-6 py-3 rounded-lg font-semibold text-lg" > Logout </button> </> ) : ( <> <Link href={'/login'}>Sign In</Link> <Link href={'/register'}>Create Account</Link> </> )} </nav> </header> ); }
方案2:监听路由变化,重新检查登录状态
如果暂时不想用Auth Context,可以让Header在路由变化时重新调用grabEmail检查登录状态(登录后通常会跳转页面,路由变化会触发检查)。
修改后的关键代码片段:
// ... 其他导入和状态定义 useEffect(() => { grabEmail(); }, [router]); // 添加router作为依赖,路由变化时重新执行 const grabEmail = async () => { try { // 统一路径为绝对路径,和登出接口保持一致 const response = await axios.get('/api/users/grabUserEmail'); setIsLoggedIn(true); } catch (error) { setIsLoggedIn(false); } }; // ... 其余代码不变
内容的提问来源于stack exchange,提问作者gj_dev
相关产品推荐
相关产品推荐

