How to remove active class when click another toggle button in React.js?

Viewed 2008

In React.js, I have page link menus and 3 toggle buttons in header.js.

All toggles buttons have div layer when clicked.

What I am trying to make is...

  1. When click a toggle button, other toggle buttons and layer has to be removed class active
  2. When click page link menu(menu1, menu2, menu3), all toggle buttons and layers has to be removed class active

What do I need to change the code ?

This is what I tried so far now.

Please help.

DEMO : https://codesandbox.io/s/49io4

header.js

import React, { useState, useEffect } from "react";

import { NavLink } from "react-router-dom";

export default function Header() {
  const [show, setShow] = useState(false);
  const [show2, setShow2] = useState(false);
  const [show3, setShow3] = useState(false);

  useEffect(() => {
    if (show) {
      document.body.classList.add("bodyRemoveScroll");
    } else {
      document.body.classList.remove("bodyRemoveScroll");
    }
  }, [show]);
  const onToggleClick = () => setShow(!show);
  const onToggleClick2 = () => setShow2(!show2);
  const onToggleClick3 = () => setShow3(!show3);

  return (
    <div className="header">
      {/* <NavLink to="/">Home</NavLink> */}
      /<NavLink to="/menu1">menu1</NavLink>/
      <NavLink to="/menu2">menu2</NavLink>/<NavLink to="/menu3">menu3</NavLink>/
      <button onClick={onToggleClick} className={show ? "active" : ""}>
        toggle1
      </button>
      <nav className={`layer1 ${show ? "active" : ""}`}>layer 1</nav>/
      <button onClick={onToggleClick2} className={show2 ? "active" : ""}>
        toggle2
      </button>
      <nav className={`layer2 ${show2 ? "active" : ""}`}>layer 2</nav>/
      <button onClick={onToggleClick3} className={show3 ? "active" : ""}>
        toggle3
      </button>
      <nav className={`layer3 ${show3 ? "active" : ""}`}>layer 3</nav>
    </div>
  );
}
2 Answers

In your example, you should unselect other values once you have clicked on some item. Other (preferable) option would be to have 1 state variable, where you will store your current active button id

const onToggleClick = () => {
  setShow(!show)
  setShow2(false);
  setShow3(false);
};

const onToggleClick2 = () => {
  setShow(false)
  setShow2(!show2);
  setShow3(false);
};

const onToggleClick3 = () => {
  setShow(false)
  setShow2(false);
  setShow3(!show3);
};

So example below looks prettier to me

import React, { useState, useEffect } from "react";

import { NavLink } from "react-router-dom";

export default function Header() {
  const [active, setActive] = useState('');

  useEffect(() => {
    if (active) {
      document.body.classList.add("bodyRemoveScroll");
    } else {
      document.body.classList.remove("bodyRemoveScroll");
    }
  }, [active]);

  const onSetActiveMenuItem = (item) => {
    if (item !== active){
      setActive(item);
    }
    else {
      setActive(''); // handle click on currently active item
    }
  };

  return (
    <div className="header">
      {/* <NavLink to="/">Home</NavLink> */}/
      <NavLink to="/menu1">menu1</NavLink>/<NavLink to="/menu2">menu2</NavLink>/
      <NavLink to="/menu3">menu3</NavLink>/
      <button onClick={() => onSetActiveMenuItem('item1')} className={active === 'item1' ? "active" : ""}>
        toggle1
      </button>
      <nav className={`layer1 ${active === 'item1' ? "active" : ""}`}>layer 1</nav>/
      <button onClick={() => onSetActiveMenuItem('item2')} className={active === 'item2' ? "active" : ""}>
        toggle2
      </button>
      <nav className={`layer2 ${active === 'item2' ? "active" : ""}`}>layer 2</nav>/
      <button onClick={() => onSetActiveMenuItem('item3')} className={active === 'item3' ? "active" : ""}>
        toggle3
      </button>
      <nav className={`layer3 ${active === 'item3' ? "active" : ""}`}>layer 3</nav>
    </div>
  );
}

I suggest only using one "show" useState, and specify a "type" useState to further clarify layer:

import React, { useState, useEffect } from "react";

import { NavLink } from "react-router-dom";

export default function Header() {
  const [show, setShow] = useState(false);
  const [type, setType] = useState("");

  useEffect(() => {
    if (show) {
      document.body.classList.add("bodyRemoveScroll");
    } else {
      document.body.classList.remove("bodyRemoveScroll");
    }
  }, [show]);
  const onToggleClick = (type) => {
    setShow(!show);
    setType(type);
  };

  return (
    <div className="header">
      {/* <NavLink to="/">Home</NavLink> */}/
      <NavLink to="/menu1">menu1</NavLink>/<NavLink to="/menu2">menu2</NavLink>/
      <NavLink to="/menu3">menu3</NavLink>/
      <button
        onClick={() => onToggleClick("layer1")}
        className={show ? "active" : ""}
      >
        toggle1
      </button>
      <nav className={`layer1 ${show && type === "layer1" ? "active" : ""}`}>
        layer 1
      </nav>
      /
      <button
        onClick={() => onToggleClick("layer2")}
        className={show ? "active" : ""}
      >
        toggle2
      </button>
      <nav className={`layer2 ${show && type === "layer2" ? "active" : ""}`}>
        layer 2
      </nav>
      /
      <button
        onClick={() => onToggleClick("layer3")}
        className={show ? "active" : ""}
      >
        toggle3
      </button>
      <nav className={`layer3 ${show && type === "layer3" ? "active" : ""}`}>
        layer 3
      </nav>
    </div>
  );
}
Related