batgerel.e
batgerel.e

Reputation: 857

How to set active class on anchor links using react

I am using react on my project. But how can i handle click event on multiple elements using state. On click all elements have same class. Here is a snippet:

const anchors = [
     {
       id: 1,
       name: "Дансны үйлчилгээ",
       key: "account-service",
     },
     {
       id: 2,
       name: "Зээлийн үйлчилгээ",
       key: "loan-service",
     },
     {
       id: 3,
       name: "Картын үйлчилгээ",
       key: "card-service",
     },
     {
       id: 4,
       name: "Даатгалын зуучлалын үйлчилгээ",
       key: "insurance-service",
     },
     {
       id: 5,
       name: "Цахим банкны үйлчилгээ",
       key: "bank-service",
     },
     {
       id: 6,
       name: "Mэдээлэл шинэчлэх",
       key: "profile-service",
     },
   ];

And the loop the array:

<div className="positions">
    {anchors.map((anchor: any) => {
         return (
          <a
             href={"#" + anchor.key}
             key={anchor.id}
             className={active ? "selected" : ""}
             onClick={(event: any) => handleClick(event)}
          >
             <img src="/images/arrow-right.svg" />
             <span>{anchor.name}</span>
          </a>
        );
    })}
</div>

And my hook is

const [active, setActive] = useState<boolean>(false);

Handle event:

  function handleClick(e: any) {
     if (e.currentTarget) setActive(!active);
     else return;
     e.stopPropagation();
  }

What i want is when i click the anchor it should be active class. But i am stuck. I can't actually get current element and it should be active.

Upvotes: 1

Views: 2292

Answers (2)

DullJoker
DullJoker

Reputation: 40

First of I would recommend using any sort of "state" for something as small as this.

You can easily get a boolean of active by doing the following in Next.js for instance (Which basically has the same router API as react):

const isCurrent: boolean = router.asPath == props.href;

Then you can add an "active" class based on this boolean or do other stuff instead like disabling the link element.

Easiest way to get this working in a DRY way is by making a wrapper for your links like this:

const NavBarLink = (props: { title: string; href: string }) => {
    const isCurrent: boolean = router.asPath == props.href;
    return (
      <Link
        href={props.href ? props.href : "/"}
        className={
          "block rounded py-0 pl-2 pr-2 hover:bg-gray-100 hover:text-gray-900" +
          (isCurrent ? " bg-gray-100 text-gray-900" : " text-white")
        }
        aria-current="page"
        aria-disabled={isCurrent}
        onClick={(e) => {
          if (isCurrent) {
            e.preventDefault();
          }
        }}
      >
        {props.title ? props.title : "--"}
      </Link>
    );
  };

Upvotes: 0

Phil
Phil

Reputation: 164795

Change your active state to record the id instead of a Boolean

const [active, setActive] = useState<number | undefined>();

Then use

<a
  href={"#" + anchor.key}
  key={anchor.id}
  className={anchor.id === active ? "selected" : ""}
  onClick={(e) => handleClick(e, anchor.id)}
>

and

function handleClick(e: React.MouseEvent<HTMLAnchorElement>, id: number) {
  e.stopPropagation()
  setActive(id)
}

Edit quirky-dream-6umx1

Upvotes: 1

Related Questions