NextJS noob here. I'm building a site with a navbar, and I want to have a different background depending on what page the user is at. I've created some states in the Navbar and a useEffect, as well as an array of pages to use a certain background for, however, when I navigate between each page, the state seems to be a page behind, and is putting the wrong background in. The Navbar.tsx is a client component. The logo component is a child of this component.
Here is the code for the parent Navbar.tsx:
'use client';
import { useState, useEffect } from 'react';
import { usePathname } from 'next/navigation';
import NavSearch from './NavSearch';
import NavLinks from './NavLinks';
import UserSection from './UserSection';
import Logo from './Logo';
import MobileMenu from './MobileMenu';
import { UserProps } from '@/utils/types';
import { pagesWhite, pagesTransparent } from '@/utils/pages';
const Navbar = ({ user }: UserProps) => {
const [scrollActive, setScrollActive] = useState(false);
const pathname = usePathname();
const [whiteLogo, setWhiteLogo] = useState(!pagesWhite.includes(pathname));
const [bgClass, setBgClass] = useState(
whiteLogo
? ' bg-black shadow-[0_13px_35px_-12px_rgba(35,35,35,0.1)] text-white'
: ' bg-white shadow-[0_13px_35px_-12px_rgba(35,35,35,0.1)] text-foreground'
);
useEffect(() => {
setWhiteLogo(!pagesWhite.includes(pathname));
setBgClass(
whiteLogo
? ' bg-black shadow-[0_13px_35px_-12px_rgba(35,35,35,0.1)] text-white'
: ' bg-white shadow-[0_13px_35px_-12px_rgba(35,35,35,0.1)] text-foreground'
);
console.log(bgClass);
}, [pathname]);
useEffect(() => {
if (pagesTransparent.includes(pathname)) {
window.addEventListener('scroll', () => {
setScrollActive(window.scrollY > 100);
});
} else {
setScrollActive(true);
}
}, []);
return (
<div
className={`fixed py-4 left-0 top-0 z-40 flex w-full items-center justify-center transition duration-500 ${
scrollActive ? bgClass : 'bg-transparent text-white'
}`}
>
<div className="container flex h-16 items-center space-x-4 sm:justify-between justify-between sm:space-x-0">
<div className="flex">
<Logo scrollActive={scrollActive} whiteLogo={whiteLogo} />
</div>
<div className="sm:flex gap-6 md:gap-10 hidden">
<NavLinks />
</div>
<div className="sm:flex hidden items-center justify-end space-x-4">
<NavSearch />
</div>
<div className="flex items-center justify-end space-x-3 ml-5">
<UserSection user={user} />
</div>
<div className="sm:hidden gap-6 md:gap-10 flex">
<MobileMenu />
</div>
</div>
</div>
);
};
export default Navbar;
And my logo.tsx is:
import Link from 'next/link';
import Image from 'next/image';
import logo from '@/public/images/logo.png';
import logoBlack from '@/public/images/logo-black.png';
const Logo = ({
scrollActive,
whiteLogo
}: {
scrollActive: boolean;
whiteLogo: boolean;
}) => {
const logoUrl = whiteLogo ? logo : scrollActive ? logoBlack : logo;
return (
<Link href="/" className="flex items-center space-x-2 sm:w-56">
<Image
src={logoUrl}
alt="Wikibeerdia"
className="w-[150px] sm:w-[230px]"
/>
</Link>
);
};
export default Logo;
How can I make this work properly?
In pathname useEffect, you are updating whiteLogo state and bgClass state. While setting bgClass whiteLogo state is not yet updated. There can be two approaches.
Approach 1: Set bgClass with the same condition you are using in whiteLogo
useEffect(() => {
setWhiteLogo(!pagesWhite.includes(pathname));
setBgClass(
!pagesWhite.includes(pathname)
? ' bg-black shadow-[0_13px_35px_-12px_rgba(35,35,35,0.1)] text-white'
: ' bg-white shadow-[0_13px_35px_-12px_rgba(35,35,35,0.1)] text-foreground'
);
console.log(bgClass);
}, [pathname]);
Approach 2: Create another useEffect with whiteLogo as dependency
useEffect(() => {
setWhiteLogo(!pagesWhite.includes(pathname));
}, [pathname]);
useEffect(() => {
setBgClass(
whiteLogo
? ' bg-black shadow-[0_13px_35px_-12px_rgba(35,35,35,0.1)] text-white'
: ' bg-white shadow-[0_13px_35px_-12px_rgba(35,35,35,0.1)] text-foreground'
);
}, [whiteLogo]);
This should resolve your issue.