Enhance class names by utilizing addEventListener within the useEffect hook

I'm having trouble with creating a hamburger button menu. The issue I'm facing is that when I click the button, nothing happens. Even though I can log something in the toogleHamburger function and see it in the console, the styling does not change as expected. If I don't use an eventListener in the useEffect, it throws a

Cannot read property 'addEventListener' of null
error. My goal is to change the styling when the button is clicked. I am utilizing module.scss for the classnames.

Nav.js

 const Nav = () => {

  useEffect(()=>{
  var navbar = document.querySelector(".navbar")
  var ham = document.querySelector(".ham")

  const toggleHamburger = () => {
    navbar.classList.toggle("showNav")
    ham.classList.toggle("showClose")
}

  ham.addEventListener("click", toggleHamburger)

  var menuLinks = document.querySelectorAll(".menuLink")
  menuLinks.forEach( 
    function(menuLink) { 
      menuLink.addEventListener("click", toggleHamburger) 
      menuLink.removeEventListener("click", toggleHamburger) 
    }
)
  })

  return (
    <div>
      <button className={`${styles.ham} ham`}></button>
      <nav className={`${styles.navbar} navbar`}>
      <ul>
        <li><a className={`${styles.menuLink} menuLink`} href="#">Home</a></li>
        <li><a className={`${styles.menuLink} menuLink`} href="#">Profile</a></li>
        <li><a className={`${styles.menuLink} menuLink`} href="#">About</a></li>
        <li><a className={`${styles.menuLink} menuLink`} href="#">Contacts</a></li>
    </ul>
    </nav>
    </div>
  );
};

                 

_nav_module.scss

.ham {
  position: absolute;
  z-index: 1000;
  top: 20px;
  right: 20px;
  width: 36px;
  height: 36px;
  border: none;
  cursor: pointer;
  background-color: transparent;
  background-image: url("https://ljc-dev.github.io/testing0/ham.svg");
  background-size: 100%;
}

.showClose {
  background-image: url("https://ljc-dev.github.io/testing0/ham-close.svg");
}

.navbar {
  position: absolute;
  top: 0;
  left: 0;
  background: black;
  width: 100vw;
  height: 100vh;
  overflow: hidden;
  color: white;
  transform: translateY(-100%);
  transition: transform 0.2s ease;
}

.showNav {
  transform: translateY(0);
}


.navbar ul {
  width: 100%;
  height: 100%;
  list-style: none;
  display: flex;
  flex-flow: column nowrap;
  justify-content: space-evenly;
  align-items: center;
}

.navbar ul li a {
  color: white;
  padding-bottom: 10px;
  border-bottom: 2px solid black;
  text-decoration: none;
  font-family: 'Open Sans', sans-serif;
  font-size: 1.2rem;
}

.navbar ul li a:hover, .navbar ul li a:focus {
  border-bottom: 2px solid white;
}

Answer №1

It is recommended to minimize the use of native DOM methods in React as much as possible, as it is often considered an anti-pattern. Instead, attach listeners inside the JSX like this:

  return (
    <div>
      <button className={`${styles.ham} ham`} onClick={toggleHamburger}></button>
      <nav className={`${styles.navbar} navbar`}>
      <ul>
        <li><a className={`${styles.menuLink} menuLink`} onClick={toggleHamburger} href="#">Home</a></li>
        <li><a className={`${styles.menuLink} menuLink`} onClick={toggleHamburger} href="#">Profile</a></li>
        <li><a className={`${styles.menuLink} menuLink`} onClick={toggleHamburger} href="#">About</a></li>
        <li><a className={`${styles.menuLink} menuLink`} onClick={toggleHamburger} href="#">Contacts</a></li>
    </ul>
    </nav>
    </div>
  );

To make the code less repetitive, you can utilize .map method to iterate over the list items:

const Item = ({ menuLink, toggleHamburger, text }) => (
  <li><a className={`${menuLink} menuLink`} onClick={toggleHamburger} href="#">Home</a></li>
);
  return (
    <div>
      <button className={`${styles.ham} ham`} onClick={toggleHamburger}></button>
      <nav className={`${styles.navbar} navbar`}>
      <ul>
        {
          ['Home', 'Profile', 'About', 'Contact'].map(
            text => <li><a className={`${styles.menuLink} menuLink`} onClick={toggleHamburger} href="#">{text}</a></li>
          )
        }
    </ul>
    </nav>
    </div>
  );

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Steps for incorporating a new element in Reactjs

While attempting to insert a new element into a React object, I encountered the following issue: const isAdmin = true let schema = { fname: Yup.string().required('Required'), lname: Yup.string().required('Required&apo ...

"Compilation error: 'not defined' is not recognized, 'no-undef

I am currently working on a login form that will fetch values from this API: However, the password field is currently empty, allowing any password to be accepted. This results in the error: Failed to compile 'userName' is not defined no-undef; ...

How to position preloader at the center in materializeCSS

Given this situation: I attempted to implement this Preloader with position:fixed and centered. My approach was as follows: .loader { position:fixed; top:50%; left:50%; -webkit-transform:translate(-50%,-50%); } <link rel="stylesheet" href="h ...

Eliminating the background color upon clicking

Here is the link structure I have set up: <ul> <li><a href="home.html"><span>home</span></a></li> </ul> However, when I click on the link, a shadow appears. I would like the link to appea ...

Error message: Upon refreshing the page, the React Router is unable to read properties of

While developing a recipe application using the Edamam recipe API, everything was functioning smoothly until an issue arose when refreshing the Recipe Detail page. The error occurs specifically when trying to refresh the page with a URL like http://localho ...

Issue encountered with Node.js 15 when using pullstate version 1.20.x

I'm facing an issue while trying to integrate pullstate.js into my React project. It seems that using it with Node.js 15 is causing compatibility problems, whereas it worked fine in Node.js 13. Can anyone offer assistance with this? In the example bel ...

When resizing the browser, HTML/CSS elements tend to shift positions :(

I've experimented with different position values like absolute, fixed, and static without success. Wrapping the element in a div didn't yield the desired result, so I'm seeking assistance to correct this. (If that is the solution) The issu ...

Enhance npm package by implementing custom functionality with React Component

I have designed an app that bears a striking resemblance to the following code: class MyCustomApp extends React.Component { constructor (props) { super(props) this.state = { tags: [ { id: 1, name: "Oranges" }, { id: 2, ...

What could be the reason for the 'if' statement not being assessed in the 'then' promise of the ajax request?

I'm facing an issue with an ajax call in my code. I have a 'then' promise set up to handle errors, where the console log returns false correctly when there is an error. However, for some reason, the if condition in the next line is not being ...

There appears to be an issue with the onmousemove function

I am currently troubleshooting an issue with a script that I wrote for my button. Interestingly, the code works flawlessly when I test it on CodePen, but I encountered an error when I attempted to run it in VSCode. Even after trying to recreate the script ...

Trigger a click based on the CSS path starting from a specific element in the DOM

I am currently developing a feature for mouse activities, such as moving the mouse, clicking, and scrolling. I want to be able to record these activities and then playback them later on. So far, I have successfully recorded mouse movement, and now I need t ...

Validating SASS based on class name

Hi there, I am fairly new to SASS and do not consider myself a programming expert. I have ten aside elements that each need different background colors depending on their class name. Even after going through the SASS documentation, I am still unable to f ...

Errors with pointer events occurring within nested iframes on Chromium 78

At first glance, it seems like a bug specific to Chromium. I have already reported this issue in a bug report. Since progress is slow on that front, I am posting a question here primarily to see if anyone else has encountered similar or related issues and ...

Troubleshooting problems with the width of a Bootstrap navbar

I'm encountering a frustrating issue with my bootstrap menu. When I include the "navbar Form" in the menu, the width of the menu extends beyond the screen width in mobile mode (when resizing the browser window or viewing on a mobile device). Interesti ...

The type 'HTMLElement' does not contain a property called 'src'

I'm having trouble displaying an image because of an error in the src property. How can I correct this declaration? import { Typography } from '@material-ui/core'; import styled from 'styled-components' const DisplayProduct = ({it ...

Switch the Drawer with the LeftIcon located in the AppBar

Greetings to all the Stackoverflow community members, I am embarking on my very first project using Material-UI with ReactJS. Successfully implemented the AppBar and Drawer functionalities (Drawer accessible through left bezel swipe). Now I am looking t ...

Vue.js does not support the usage of external JSON files directly within HTML documents

I'm encountering issues fetching data from an external JSON file for a specific variable. I suspect that the problem lies in using Vue.js within the HTML, as it seems to be having trouble interpreting my code correctly.:joy: jsfiddle Additionally, I ...

Is it feasible to combine various front-end applications - one developed in Vue and another in React - using just one Laravel backend?

Recently, I have taken over a laravel project that includes a vue application integrated within it (located inside resources/assets/js) using laravel-mix. My task now is to implement some front-end features with react. I am curious if it's possible to ...

Utilizing the state as a condition within the useEffect to update the component

Is there a way to automatically hide the mobile menu when the URL changes in ReactRouter? I have noticed that I get a warning for not tracking mobileOpen as a dependency, but strangely the code still works fine. const Navbar: React.FC<Props> = props ...

Triumph Grid Background for Charts

Can Victory charts be used to create a grid layout similar to this? https://i.stack.imgur.com/DMxKu.png Currently, I'm only able to achieve a grid with both vertical and horizontal lines on top of my bars like this: https://i.stack.imgur.com/ywDFL. ...