You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

解决NextJS页面切换时Navbar样式切换延迟问题

问题:Next.js 页面切换时 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;

原因分析

问题出在页面切换时没有触发样式更新逻辑:

  1. 当前只在组件挂载时和滚动事件中调用状态更新函数,但 Next.js 客户端导航不会重新挂载组件,路径变化时不会主动执行这些函数。
  2. 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;

优化点说明

  1. 合并状态:把 color 和 image 合并为 isActive,减少重复的状态管理逻辑。
  2. 监听路径变化:通过 usePathname 获取实时路径,路径切换时自动触发状态更新。
  3. 简化回调:将重复的判断逻辑整合到一个函数中,避免代码冗余。
  4. 正确设置依赖:让 useEffect 依赖 pathname,确保路径变化时重新执行状态更新逻辑。

内容的提问来源于stack exchange,提问作者userunknown

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 11:12:14