2

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>
  );
}
user1833620
  • 751
  • 1
  • 10
  • 30

2 Answers2

3

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>
  );
}
  • Thank you. This works perfect. I have one more question, how to remove active class on toggle button when click menu1, menu2, menu3 page link ? – user1833620 May 07 '21 at 16:56
  • 1
    @user1833620 I see you have already done that on your codesandbox, am I right? You have just added `onClick={resetToggle}` if you need to set navLink inactive when you click on buttons, then you need to update your current URL, you can check [this](https://stackoverflow.com/questions/42123261/programmatically-navigate-using-react-router-v4) answer to do that – Dmytro Krasnikov May 07 '21 at 17:07
  • Yes. I tried onClick={resetToggle} with your example :) Thank you Works Goood :) – user1833620 May 07 '21 at 17:15
  • 1
    I have updated my answer, you can check the second part and use 1 state variable as you shouldn't have two active items in one moment – Dmytro Krasnikov May 07 '21 at 17:19
2

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>
  );
}
anonymous
  • 161
  • 3
  • 11