解决NextJS页面切换时Navbar样式切换延迟问题
我用 Next.js 实现了一个导航栏,逻辑是当页面滚动到950px以下,或者当前路径是 /lodge 时,切换导航栏的文字颜色和图标。但现在遇到一个问题:页面切换时(比如从首页跳转到 /lodge),导航栏的样式不会立刻更新,必须手动滚动一下页面才会触发样式切换。
当前代码如下:
'use client' import Image from "next/image" import Link from "next/link" import Container from "../Container" import { useState, useEffect, useCallback } from "react"; import { useRouter } from "next/navigation"; const Navbar = () => { const [color, setColor] = useState(false) const changeColor = useCallback(() => { if (window.scrollY >= 950 || window.location.pathname.includes('/lodge')) { setColor(true); } else { setColor(false); } }, []); useEffect(() => { changeColor(); window.addEventListener('scroll', changeColor); return () => { window.removeEventListener('scroll', changeColor); }; }, []); const [image, setImage] = useState(false) const changeImage = useCallback(() => { if (window.scrollY >= 950 || window.location.pathname.includes('/lodge')) { setImage(true); } else { setImage(false); } }, []); useEffect(() => { changeImage(); window.addEventListener('scroll', changeImage); return () => { window.removeEventListener('scroll', changeImage); }; }, []); return ( <div className="fixed w-full backdrop-blur-sm shadow-sm"> <div className="py-4 border-b-[2px]"> <Container> <div className="flex flex-row items-center justify-between gap-4"> <Link href="/"> {image ? ( <Image className="" src="/images/logo-b.svg" alt="logo-b" width={132} height={58}/> ) : ( <Image className="" src="/images/logo.svg" alt="logo" width={132} height={58}/> )} </Link> <div className="text-2xl text-white font-medium xl:pl-[632px] md:block hidden"> <Link href="/lodge" className={color ? 'text-[#313131]' : 'text-white'} > LODGE </Link> </div> <div className="text-2xl text-white font-medium md:block hidden"> <div className={color ? 'text-[#313131]' : 'text-white'}> <Link href="/blog"> OUR BLOG </Link> </div> </div> <div className="text-white text-2xl font-medium flex flex-row items-center gap-3"> <div className="relative sm:w-5 sm:h-5 md:w-5 md:h-5"> {image ? ( <Image src="/images/tel-b.svg" alt="tel" width={24} height={24}/> ) : ( <Image src="/images/tel.svg" alt="tel-b" width={24} height={24}/> )} </div> <div className=""> <div className={color ? 'text-[#313131]' : 'text-white'}> NUM </div> </div> </div> <div className="text-2xl text-white font-medium flex flex-row items-center gap-3"> <div className={color ? 'text-[#313131]' : 'text-white'}> <div className="sm:block cursor-pointer"> EN </div> </div> <div className={color ? 'text-[#313131]' : 'text-white'}> | </div> <div className={color ? 'text-[#313131]' : 'text-white'}> <div className="sm:block cursor-pointer"> ES </div> </div> </div> </div> </Container> </div> </div> ) } export default Navbar;
原因分析
问题出在页面切换时没有触发样式更新逻辑:
- 当前只在组件挂载时和滚动事件中调用状态更新函数,但 Next.js 客户端导航不会重新挂载组件,路径变化时不会主动执行这些函数。
window.location.pathname会随路径变化更新,但你的回调函数没有监听路径变化,只有滚动时才会检查路径状态。
解决方案
优化代码:用 usePathname 监听路径变化
Next.js 提供的 usePathname 钩子可以实时获取当前路径,并且路径变化时会触发组件重新渲染。我们可以利用它来自动更新导航栏状态:
'use client' import Image from "next/image" import Link from "next/link" import Container from "../Container" import { useState, useEffect, useCallback } from "react"; import { usePathname } from "next/navigation"; const Navbar = () => { const pathname = usePathname(); // 合并 color 和 image 状态,减少重复逻辑 const [isActive, setIsActive] = useState(false); // 统一状态判断逻辑 const updateNavbarState = useCallback(() => { const shouldActivate = window.scrollY >= 950 || pathname.includes('/lodge'); setIsActive(shouldActivate); }, [pathname]); useEffect(() => { // 组件挂载时先执行一次 updateNavbarState(); // 绑定滚动事件 window.addEventListener('scroll', updateNavbarState); return () => { window.removeEventListener('scroll', updateNavbarState); }; }, [pathname, updateNavbarState]); // 依赖 pathname,路径变化时重新执行 return ( <div className="fixed w-full backdrop-blur-sm shadow-sm"> <div className="py-4 border-b-[2px]"> <Container> <div className="flex flex-row items-center justify-between gap-4"> <Link href="/"> {isActive ? ( <Image src="/images/logo-b.svg" alt="logo-b" width={132} height={58}/> ) : ( <Image src="/images/logo.svg" alt="logo" width={132} height={58}/> )} </Link> <div className="text-2xl text-white font-medium xl:pl-[632px] md:block hidden"> <Link href="/lodge" className={isActive ? 'text-[#313131]' : 'text-white'} > LODGE </Link> </div> <div className="text-2xl text-white font-medium md:block hidden"> <Link href="/blog" className={isActive ? 'text-[#313131]' : 'text-white'}> OUR BLOG </Link> </div> <div className="text-white text-2xl font-medium flex flex-row items-center gap-3"> <div className="relative sm:w-5 sm:h-5 md:w-5 md:h-5"> {isActive ? ( <Image src="/images/tel-b.svg" alt="tel" width={24} height={24}/> ) : ( <Image src="/images/tel.svg" alt="tel-b" width={24} height={24}/> )} </div> <div className={isActive ? 'text-[#313131]' : 'text-white'}> NUM </div> </div> <div className="text-2xl text-white font-medium flex flex-row items-center gap-3"> <div className={isActive ? 'text-[#313131]' : 'text-white'}> <div className="sm:block cursor-pointer">EN</div> </div> <div className={isActive ? 'text-[#313131]' : 'text-white'}>|</div> <div className={isActive ? 'text-[#313131]' : 'text-white'}> <div className="sm:block cursor-pointer">ES</div> </div> </div> </div> </Container> </div> </div> ) } export default Navbar;
优化点说明
- 合并状态:把
color和image合并为isActive,减少重复的状态管理逻辑。 - 监听路径变化:通过
usePathname获取实时路径,路径切换时自动触发状态更新。 - 简化回调:将重复的判断逻辑整合到一个函数中,避免代码冗余。
- 正确设置依赖:让
useEffect依赖pathname,确保路径变化时重新执行状态更新逻辑。
内容的提问来源于stack exchange,提问作者userunknown
相关产品推荐
相关产品推荐

