My website keeps crashing because the "wheel" event is being constantly triggered

import React, { useEffect, useState } from "react";
import "./Skill.css";
import { Fade } from "react-reveal";
function Skill({ name, color }) {
  const [style, setStyle] = useState({ borderBottom: `4px solid ${color}` });
  
  window.addEventListener("wheel", () => {
    let scroll = window.scrollY;
    console.log(scroll);
    if (scroll >= 1300) {
      setStyle({
        animation: "load 2s ease-out",
        display: "block",
        borderBottom: `4px solid ${color}`,
      });
    }
  });
  return (
    <>
      <div className="skill">
        <Fade bottom>
          <div className="Skill__logo">
            <img
              className="logo__img"
              src="./images/html-5-logo-svgrepo-com.svg"
              alt=""
            />
          </div>
          <div className="skills__about">
            <div className="skillitem">
              <div className="skill__set">
                <div className="skill__Name" style={{ color: color }}>
                  {name}
                </div>
              </div>
              <div style={style} className="loading__skill"></div>
            </div>
          </div>
        </Fade>
      </div>
    </>
  );
}

export default Skill;

Need assistance with my code as the wheel event seems to be firing infinitely and causing my application to crash. Any insights on how to resolve this issue would be greatly appreciated.

Answer №1

Once the setStyle function is triggered within the wheel event listener callback, it triggers a refresh of the Skill component, which in turn invokes

window.addEventListener("wheel", () => {
again. This results in another callback being added to the window object, causing the initial wheel event to be triggered again, creating an infinite loop.

To resolve this issue, a simple solution is to place the logic that should only run during the initial render inside a useEffect hook with an empty dependency array, like this:

useEffect(() => {
  window.addEventListener("wheel", () => {
    let scroll = window.scrollY;
    console.log(scroll);
    if (scroll >= 1300) {
      setStyle({
        animation: "load 2s ease-out",
        display: "block",
        borderBottom: `4px solid ${color}`,
      });
    }
  });
}, []);

While the above solution works, it is a temporary fix. It is important to control window-related properties in the top-most parent component of the application to prevent global variable pollution and ensure the maintainability of event listeners.

Answer №2

One potential explanation could be the frequent firing of the wheel event during scrolling. To address this issue, you can experiment with implementing a debouncing script.

// ...more code
function debounce(func, timeout = 300){
  let timer;
  return (...args) => {
    clearTimeout(timer);
    timer = setTimeout(() => { func.apply(this, args); }, timeout);
  };
}
 window.addEventListener("wheel", debounce(() => {
    let scroll = window.scrollY;
    console.log(scroll);
    if (scroll >= 1300) {
      setStyle({
        animation: "load 2s ease-out",
        display: "block",
        borderBottom: `4px solid ${color}`,
      });
    }
  }));
// ...more code

This particular implementation sets a limit of firing the event every 300 milliseconds, approximately every 0.3 seconds.

Answer №3

Just a friendly reminder, each time you update state or modify a prop, a new render cycle is triggered. The issue lies in your component where you are attaching a listener to the scroll event during every render cycle without removing it. Moreover, one of the actions within your listener function is to update state, leading to another render, and subsequently creating another listener, resulting in a potential infinite loop scenario.

The recommended approach is to utilize the useState hook to attach your listener during the initial render only and provide a function to remove the listener when the component unmounts:

// define handleWheel outside your function or use `useCallback` for a persistent reference
const handleWheel = () => {
  let scroll = window.scrollY;
  console.log(scroll);
  if (scroll >= 1300) {
    setStyle({
      animation: "load 2s ease-out",
      display: "block",
      borderBottom: `4px solid ${color}`,
    });
  }
}

// later in your component:
useState(() => {
  window.addEventListener("wheel", handleWheel);
  return () => window.removeEventListener("wheel", handleWheel); // to be executed on component unmount
}, []); // empty array ensures it runs only during the initial render

Answer №4

There are many excellent answers, but none have mentioned a way to prevent re-rendering. Allow me to suggest a different approach. Instead of using window.addEventListener("wheel") to detect scrolling and applying a style when scrollY > 1300, which triggers re-rendering each time, we can use useRef() to store a value that indicates whether the state change is necessary. By doing so, we can avoid unnecessary re-renders caused by repeatedly setting the style as we scroll. Changes to the ref value do not trigger re-renders; only changes to the state do.

For more information on useRef(), you can visit this link.

Below is a code example that demonstrates this approach:

You can also utilize React.Memo() and provide a comparison function to prevent re-renders triggered by continuous scrolling events and style changes.

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

Unable to access $_SESSION variable when making AJAX request from a different port

After creating a website with PHP on port 80 (index.php) and setting the session variable with the userid upon login, I encountered an issue when clicking on a link that redirected me to port 8080, which is where a JavaScript file containing node.js proces ...

Resolving VSCode WebViewPanel access issues through a corporate proxy

I am currently utilizing the "C4 DSL Extension" in VSCode to display previews of my architecture diagrams. These previews are generated through the WebviewPanel functionality. If you're interested, you can access the source code here: While everythin ...

Can the system automatically generate and display a new user ID right after a form is submitted?

Once users have submitted the basic information in a form, how can I ensure that the newly created userID is displayed in a hidden field on the header page? The initial form collects Name, Phone, and Email details. Upon submission, the 'userID' ...

Ways to compel links to open in Internet Explorer

In one of my chatbot messages, I have included a link to a web app that is only compatible with Internet Explorer. My chatbot runs on Google Chrome, so when the user clicks on the link, it opens in a new Chrome tab instead of in IE, where it should open f ...

Display the size of the data array in VueJS once the data has been retrieved from the API

Using Vue JS, I have been attempting to retrieve data from an API. My goal is to determine the length of the array and then log it to the console using a method. However, every time I try to do this, the value logged is always "0" instead of the actual le ...

Transforming dynamic class based on state value from React to TypeScript

I'm trying to implement this React function in TypeScript, but I'm encountering errors. const ListItem = ({ text }) => { let [showMore, setShowMore] = useState(false); return ( <div className="item"> ...

Access external variables in next.js outside of its environment configuration

Currently, I am developing my application using next js as the framework. While my environment variables work smoothly within the context of next js, I am facing a challenge when it comes to utilizing them outside of this scope. An option is to use dotenv ...

Trouble Viewing Image File

I am facing an issue where I cannot upload an image file from my computer onto my HTML file, as it is not showing up in the browser. However, when I link an image file from the web, it works perfectly fine. I have double-checked the file path and ensured ...

Creating and deleting HTML elements in a dynamic array format

My current approach involves utilizing jQuery and JavaScript for the purpose of dynamically adding and removing HTML elements. Specifically, I am focusing on the removal of particular HTML elements. The code snippet is as follows: $(document).ready(fun ...

Error message, 'props is incompatible with empty', appears when attempting to create a Component without passing any props

I have a component that is contained within a react-redux "connect" wrapper. All the props of the component are supplied by mapStateToProps and MapDispatchToProps, so no "ownProps" are passed to the component. Despite this setup, I am encountering the fol ...

React: Function is missing a return type declaration. eslint plugin @typescript-eslint urges for explicit function return types

I'm just starting out with Typescript in React. I've created a simple functional component, but eslint is giving me an error saying that the return type for the functional component itself is missing. Can anyone help me figure out what I'm d ...

Finding a solution for odd css box-sizing behavior in Bootstrap 3 and eliminating the unwanted horizontal slider

My website built with Bootstrap 3 looks great in Internet Explorer, but in Chrome and Firefox there seems to be a persistent bottom slider and a small area on the right side that remains visible even when I scale down to 1%. I suspect this issue is relate ...

Execute the cucumber cli programmatically in the index.js file of a node application

Recently, I received an automation framework built in CucumberJS and Node with Selenium. However, the framework is using an outdated version of Cucumber that relies on promises. Wanting to take advantage of the latest synchronous step feature, I decided to ...

How to Pause or Temporarily Halt in Jquery?

Looking to lift the object up, wait 1000ms, and then hide it. I found this snippet of code: $("#test").animate({"top":"-=80px"},1500) .animate({"top":"-=0px"},1000) .animate({"opacity":"0"},500); However, using ".animate({"to ...

Create a Vue component that utilizes the v-for directive to iterate through a list of items, passing data from a

Imagine having two arrays with a similar structure like this: const individuals = [{name: "Jane Doe", id: "0001"},{name: "John Doe", id:"0002"}, {name: "Sam Smith", id: "0003"}, {name: "Joe ...

Having trouble with an unknown cipher when using the crypto module?

Encountering difficulty encrypting with aes-256 using cipher - getting an error stating unknown cipher. Any insights on what may be missing in the code below? index.js function encryptPaymentId(specialtyID, paymentId) { const convertToStrin ...

Error: Attempting to access 'string' property of an undefined object when utilizing griddle version 1.0.3 in conjunction with react version 16.2.0

Trying to integrate griddle-react 1.0.3 with react 16.2.0 but encountering the error "Typeerror: Cannot read property 'string' of undefined". How can this error be resolved? Is it recommended to switch to griddle 0.8.1 for react 16.2.0 or is the ...

Toggling visibility in React Native by pressing a button

i have a toolbar in my react-native app that looks like this: https://i.stack.imgur.com/Msu4t.png Whenever I click on the search icon, I want to display an input text field like this: https://i.stack.imgur.com/HPwTB.png I've tried several examples ...

the function fails to run upon clicking the button again

Here is the current function in use: function beTruthful() { if (document.getElementById("about").style.opacity = "0") { document.getElementById("about").style.opacity = "1"; } else { document.getElementById("about").style.opacity ...

Encountering a "Cannot GET /PATH" error while developing a NUXT application due to a DOT present in

In my nuxt application, I encountered a peculiar issue. When I execute npm run dev, everything functions properly. However, after running npm run build and then npm run start, I face the error message stating cannot GET [path of the page here] I noticed t ...