Home > OS >  rewriting javascript event listener and toggling of classlist in reactjs
rewriting javascript event listener and toggling of classlist in reactjs

Time:08-10

Please help, I have been trying to write the following code in react syntax but I don't seem to know how to do that and all search I've made online isn't helping

useEffect(() => {
    const menuBtn = document.getElementById('menu-btn');
    const menu = document.querySelector('.menu')

    menuBtn.addEventListener('click', () =>{
    menu.classList.toggle('menu-open')
    })    
    }, []);

    useEffect(()=>{
    const navbar = document.getElementById('navbar')
    const offset = 50

    window.addEventListener("scroll", () =>{
      if(pageYOffset > offset){
        navbar.classList.add('navbar-active')
      }else{
        navbar.classList.remove('navbar-active')
      }
    })
    }, [])

I want to change it because I keep getting the error below

[webpack.cache.PackFileCacheStrategy] Skipped not serializable cache item 'Compilation/modules|/home/kimmoramicky/Desktop/fts_portfolio/node_modules/next/dist/build/webpack/loaders/css-loader/src/index.js??ruleSet[1].rules[2].oneOf[7].use[1]!/home/kimmoramicky/Desktop/fts_portfolio/node_modules/next/dist/build/webpack/loaders/postcss-loader/src/index.js??ruleSet[1].rules[2].oneOf[7].use[2]!/home/kimmoramicky/Desktop/fts_portfolio/node_modules/bootstrap/dist/css/bootstrap.min.css': No serializer registered for Warning while serializing webpack/lib/cache/PackFileCacheStrategy.PackContentItems -> webpack/lib/NormalModule -> Array { 1 items } -> webpack/lib/ModuleWarning -> Warning

but when I comment that part out, I don't get the error. Also, the code doesn't work as expected when the page is loaded again. Below is the complete code for clearer understanding

import React, {useState, useEffect, useRef} from 'react'
import Link from 'next/link'
import { getPosts, getTags, getCategories } from '../services';
import { useRouter } from 'next/router';
import 'react-ionicons'
import 'react-ionicons'
import { FaFacebookSquare, FaGithubSquare, FaInstagramSquare, FaYoutubeSquare } from 'react-icons/fa'
import {ImMenu} from 'react-icons/im'
import {BiSearchAlt} from 'react-icons/bi'
import Button from 'react-bootstrap/Button';
import Container from 'react-bootstrap/Container';
import Form from 'react-bootstrap/Form';
import Nav from 'react-bootstrap/Nav';
import Navbar from 'react-bootstrap/Navbar';
import NavDropdown from 'react-bootstrap/NavDropdown';
import { filter } from 'domutils';


const Header = () => {

  useEffect(() => {
    const menuBtn = document.getElementById('menu-btn');
    const menu = document.querySelector('.menu')

    menuBtn.addEventListener('click', () =>{
    menu.classList.toggle('menu-open')
    })    
    }, []);

    useEffect(()=>{
    const navbar = document.getElementById('navbar')
    const offset = 50

    window.addEventListener("scroll", () =>{
      if(pageYOffset > offset){
        navbar.classList.add('navbar-active')
      }else{
        navbar.classList.remove('navbar-active')
      }
    })
    }, [])

    return (
      <div className='header1'>

      <video id='headerVideo' loop={true} autoplay="autoplay" muted>
        <source src="/vidfy-african-cheerful-young-stylish-man-and-w_1920x1080.mp4" type="video/mp4"></source>
      Your browser does not support the video tag.
      </video>
    
    <div>
      <nav id='navbar'>
        <div className="menu">
          <div>
            <a href="#" className='brand'>Menu</a>
            <ul>
              <li><a href="#">Blog</a></li>
              <li><a href="#">What's New</a></li>
              <li><a href="#">Categories</a></li>
            </ul>

            <ul>
              <li><a href="#">Projects</a></li>
              <li><a href="#">News</a></li>
              <li><a href="#">Store</a></li>
              <li><a href="#">About</a></li>
              <li><a href="#">Contact</a></li>
            </ul>

            <ul className='social-media'>
              <li><a href="#">
              <FaFacebookSquare />
              </a></li>
              <li><a href="#">
              <FaInstagramSquare />
              </a></li>
              <li><a href="#">
              <FaGithubSquare />
              </a></li>
              <li><a href="#">
              <FaYoutubeSquare />
              </a></li>
            </ul>

            <form action="">
              <div className="input-wrap">
                <input type="search" placeholder='Search...' />
                <button type='submit'>
                  <BiSearchAlt />
                </button>
              </div>
            </form>

          </div>
        </div>

        <div className="container">
          <a href="#" className="logo"><img src="/logo.png" alt="logo" /></a>
          <div className="container-inner">

            <ul>
              <li><a href="#">Home</a></li>
              <li><a href="#">Home</a></li>
              <li><a href="#">Home</a></li>
            </ul>

            <form action="">

              <div className="input-wrap">
                <input type="search" placeholder='Search...' className='text-is-white' />
                <button type='submit'>
                <BiSearchAlt />
                </button>
              </div>

            </form>
          </div>
          <ImMenu className='fa-bars' id='menu-btn' />
        </div>
      </nav>
    </div>

    <div className="headText">
      <p>Grow your business and ideas with KimmoTech</p>
    </div>
    </div>
    )
}

export default Header
  

CodePudding user response:

I would recommend to switch from useEffect to using useState to manage the state of your components including classes. Also React provides an easy and smooth way to manage your event handlers such as onClick.

Here is an example of how I would approach your problem, it's not going to be your code exactly but hopefully you can replicate the approach to work with you code:

import React, { useState } from 'react';

const Example = () => {
  const [classes, setClasses] = useState('class-1');

  const handleToggleClasses = () => {
    setClasses(classes === 'class-1' ? 'class-2' : 'class-1')
  }

  return (
    <>
      <div className={classes}>
        my classes will change when the button is clicked
      </div>
      <button onClick={handleToggleClasses}>
        click me to toggle classes
      </button>
    </>
  )
}

This button in this code has a an onClick handler which is equivalent to assigning it an event listener using vanilla JS like you did in your useEffect and I pass to it the handleToggleClasses function which just toggles between the classes using useState to keep track of that. It's cleaner, more performant and concise.

you can read more about handling events here

I hope that helps!

CodePudding user response:

so you have a bunch of stuff you should not do that way:

First:

const menuBtn = document.getElementById('menu-btn');

Should be:

export const Component = () => {

const [menuOpen, setMenuOpen = useState(false)
const handleMenuButtonClick = () => setMenuOpen(!menuOpen)

return (
  …
    <div className={‘menu ${menuOpen ? ‘menu-open’ : ‘menu-closed’}’}/>
    <button onClick={handleMenuButtonClick} />
  …
)

Then this:

window.addEventListener("scroll", () =>{
      if(pageYOffset > offset){
        navbar.classList.add('navbar-active')
      }else{
        navbar.classList.remove('navbar-active')
      }
    })
    }, [])

This is better to use as hook and when you do that you have two things you should have in mind, first one this should be DEBOUNCED otherwise you’l have quite nasty perf hit, second when you subscribe to event like that you have to also unsubscribe:


cons [scrollActive, setScrollActive] = useState(false)

useEffect(() => {
   const scroll = window.addEventListener(‘scroll’, (e) => setScrollActive(e > condition));
  return () => winodw.removeEventListener(scroll)
}, [])

… 
  <navbar classNsme={‘navbar ${scrollActive ? ‘scroll-active’ : ‘’}}/>

They would look more like react then it is right now…

CodePudding user response:

The issue occurred because you used webpack on react app. It'll be disappeared if you create the app with "create-react-app". Hope it'll be helpful for you.

  • Related