skip to Main Content

I’ve a nextjs custom component that adds the locale before the pathname of the page when clicked and adds custom style for the active link..

here is the component

"use client";

import { useLocale } from "next-intl";
import Link from "next/link";
import { usePathname } from "next/navigation";
import React, { useEffect, useState } from "react";

export default function RoutingLink({
    children,
    href,
    className,
    activeClass
}: {
    children: React.ReactNode;
    href: string;
    className?: string;
    activeClass?: string;
}) {
    const currentLocale = useLocale();
    const pathname = usePathname();
    const [isLinkActive, setIsLinkActive] = useState<boolean>(false);
    useEffect(
        () => {
            if (pathname.slice(1) === href) {
                setIsLinkActive(true);
            }

            () => {
                setIsLinkActive(false);
            };
        },
        [pathname]
    );

    function handleActiveClass() {
        if (isLinkActive) {
            if (activeClass) {
                return activeClass;
            } else {
                return "text-primaryHover";
            }
        } else {
            return "";
        }
    }

    return (
        <Link href={`/${currentLocale}/${href}`} className={`${className} ${handleActiveClass()}`}>
            {children}
        </Link>
    );
}

the problem happened after I created a sidebar tab component *please have a look at the screenshot * Nav Tabs with different hrefs, when I click at one link it becomes active and style changes but after I click at another one the previous link still have the active style as well.

I’ve tried to use useEffect() passing current pathname as dependency library to it, so that whenever the url is changed the active class should be changed and callback function should be called so that active style disappears from previous link.

2

Answers


  1. It seems like the issue might be related to the way you’re setting and updating the isLinkActive state in your useEffect hook. The cleanup function in the useEffect seems to be incorrectly structured. Also, the useEffect might not be triggering as expected due to the way pathname is compared to href.

    Let’s try a different approach. Instead of relying on useEffect for determining the active link, you could calculate the active status directly in the component by comparing the pathname with the href prop.

    Here’s an updated version of your component that might resolve the issue:

    "use client";
    import { useLocale } from "next-intl";
    import Link from "next/link";
    import { usePathname } from "next/navigation";
    import React from "react";
    
    export default function RoutingLink({
        children,
        href,
        className,
        activeClass
    }: {
        children: React.ReactNode;
        href: string;
        className?: string;
        activeClass?: string;
    }) {
        const currentLocale = useLocale();
        const pathname = usePathname();
    
        // Check if the link is active based on the current pathname
        const isLinkActive = `/${currentLocale}/${href}` === pathname;
    
        function handleActiveClass() {
            return isLinkActive && activeClass ? activeClass : "";
        }
    
        return (
            <Link href={`/${currentLocale}/${href}`} passHref>
                <a className={`${className} ${handleActiveClass()}`}>
                    {children}
                </a>
            </Link>
        );
    }
    

    This approach calculates the isLinkActive status directly in the component based on the comparison between the constructed link (/${currentLocale}/${href}) and the pathname. It then applies the active class accordingly without relying on useEffect. This should update the active class when the pathname changes.

    Give this a try and see if it resolves the issue with the active class not updating when the URL changes.

    Login or Signup to reply.
  2. I think Tailwind won’t recall the function even your component re-renders. Moreover, if there are multiple RoutingLink on the same page, then when clicking on other link, the old RoutingLink is still mounted, means the callback function on useEffect won’t get called.

    I would suggest you refactor a bit:

    const pathname = usePathname();
    const isActive = pathname.slice(1) === href;
    const linkClass = isActive ? activeClass || "text-primaryHover" : "";
    
    return (
            <Link href={`/${currentLocale}/${href}`} className={`${className} ${linkClass}`}>
                {children}
            </Link>
    );
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search