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>
  );
}

2 Answers 2

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>
  );
}
Sign up to request clarification or add additional context in comments.

4 Comments

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 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 answer to do that
Yes. I tried onClick={resetToggle} with your example :) Thank you Works Goood :)
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
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>
  );
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.