Multiple re-renders of component in React when adding event listeners

I’m trying to build a tourism app using Next.js, and across the Wilayas Component I stumbled into a very weird bug, so inside the component I fetch an svg map, for each zone of the svg map I add an event listener through a useEffect as you can see down below, the event should cause an animation of sliding which works as you can see over here Wilayas Sliding

But if you open the console you’ll be able to see hello displaying from console.log i put in the useEffect to debug my app, with each click it increments but rather with one, it keeps doubling, so to say i you click once, hello is displayed once, if you click twice it’s displayed 3 times, if you click four times you get Hello 15 times meaning 15 re-renders and as you click this keeps escalating to a point causing the website to block!

My Wilayas Component :

const Wilayas = ({ region }: { region: any }) => {
  const [wilayas, setWilayas] = useState<HTMLElement[]>([]);
  const [currentIndex, setCurrentIndex] = useState(0);
  const [left, setLeft] = useState(0);
  const [back, setBack] = useState(false);
  const [forward, setForward] = useState(true);
  const sectionRef = useRef<HTMLUListElement>(null);

  const goBack = () => {
    setCurrentIndex(currentIndex - 1);
    if (sectionRef.current) {
      sectionRef.current.style.transform = `translate(${
        left + 27.278566666666666
      }vw)`;
    }

    const updatedWilayas = [...wilayas];
    updatedWilayas.forEach((wilaya) => wilaya?.classList.add("lighten"));
    updatedWilayas[currentIndex]?.classList.remove("darken");
    updatedWilayas[currentIndex - 1]?.classList.add("darken");
    updatedWilayas[currentIndex - 1]?.classList.remove("lighten");
    setWilayas(() => updatedWilayas);

    setLeft(left + 27.278566666666666);
    if (currentIndex === 1) {
      setBack(false);
    } else {
      setForward(true);
    }
  };

  const goForward = () => {
    setCurrentIndex(currentIndex + 1);
    if (sectionRef.current) {
      sectionRef.current.style.transform = `translate(${
        left - 27.278566666666666
      }vw)`;
    }

    const updatedWilayas = [...wilayas];
    updatedWilayas.forEach((wilaya) => wilaya.classList.add("lighten"));
    updatedWilayas[currentIndex]?.classList.remove("darken");
    updatedWilayas[currentIndex + 1]?.classList.add("darken");
    updatedWilayas[currentIndex + 1]?.classList.remove("lighten");
    setWilayas(() => updatedWilayas);

    setLeft(left - 27.278566666666666);
    if (currentIndex === 8) {
      setForward(false);
    } else {
      setBack(true);
    }
  };

  const goToExactRegion = useCallback(
    (index: number) => {
      setCurrentIndex(index);
      const updatedWilayas = [...wilayas];
      console.log("hello");

      updatedWilayas.forEach((wilaya) => wilaya.classList.add("lighten"));
      updatedWilayas[currentIndex]?.classList.remove("darken");
      updatedWilayas[index]?.classList.add("darken");
      updatedWilayas[index]?.classList.remove("lighten");

      if (index < currentIndex) {
        sectionRef.current!.style.transform = `translate(${
          left + (currentIndex - index) * 27.278566666666666
        }vw)`;
        if (index === 0) {
          setBack(false);
        }
        setForward(true);
        setLeft(left + (currentIndex - index) * 27.278566666666666);
      } else if (index > currentIndex) {
        sectionRef.current!.style.transform = `translate(${
          left - (index - currentIndex) * 27.278566666666666
        }vw)`;
        if (index === 9) {
          setForward(false);
        }
        setBack(true);
        setLeft(left - (index - currentIndex) * 27.278566666666666);
      }

      setWilayas(() => updatedWilayas);
    },
    [wilayas]
  );

  const handleSwitch = (index: number) => () => {
    goToExactRegion(index);
  };

  useEffect(() => {
    if (document.getElementById("region") !== null) {
      const fetching = async () => {
        const response = await fetch(
          `https://ik.imagekit.io/vaqzdpz5y/assets/images/${region.id}/3.svg`
        );
        const svgContent = await response.text();
        console.log("hello");
        document.getElementById("region")!.innerHTML = svgContent;
        document.getElementById("svg2")!.style.width = "100%";
        const wilayat = [];
        for (let i = 1; i < 11; i++) {
          const wilaya = document.getElementById(`${i}`);
          if (wilaya) wilayat.push(wilaya);
        }
        setWilayas(wilayat);
      };
      fetching();
    }
  }, []);

  useEffect(() => {
    const wilayat: HTMLElement[] = [];
    for (let i = 1; i < 11; i++) {
      const wilaya = document.getElementById(`${i}`);
      if (wilaya) {
        wilaya.addEventListener("click", handleSwitch(i - 1));
        wilayat.push(wilaya);
      }
    }

    return () => {
      wilayat.forEach((wilaya, i) => {
        wilaya.removeEventListener("click", handleSwitch(i - 1));
      });
    };
  }, [wilayas, handleSwitch]);
return (
<div>
   ...
   <div id="region" className="w-[51.5625vw]"></div>
</div>
)

In the last div i add my SVG Map.
I want to highlight the fact that if you check the Destinations page Destinations Page which has the svg inside the code instead of fetching it, and with adding the same event listeners with the same functions, but in this case using the onClick React prop everything works perfectly fine, and as you might see, i can’t just implement the SVG Map of each region as it’ll result into like 11 files, so I would really appreciate your help!

Sense for color changes in video element with js

I have a video element with a source of a black and white flash video. ie. A video with a background which goes black and after sometime it goes white again and vice versa (flashing video of black and white). What i want to do is detect when the video’s background goes white. And log the data on the console. Please help me solve this problem. Thanks in advance 🙂

i18n-unused showing used translation

I use react-i18next in my project.

Referencing on this comment,
Now I use i18n-unused to identify unused translation.

module.exports = {
  localesPath: 'assets/locales',
  srcPath: 'src',
};

When I run i18n-unused display-unused, it shows that lots of translations are unused, but actually most of those translations are being used.

Result

Unused translations count: 840
...
'translation.header.documents' 
...

In my code

import { useTranslation } from 'react-i18next';
...
const { t } = useTranslation();
...

return (
  <Header title={t('header.documents')}/>
)

Is there any solution for it?

Re-resizable preventing flatlist from scrolling

Resizable from the re-resizable package is preventing my Flatlist from scrolling. When the list has enough elements to require scrolling, it doesn’t start to scroll. This behavior doesn’t happen when the resizable element isn’t there. The documentation for Resizable doesn’t mention scrolling.

<Resizable
      style={style.mainViewExpanded}
      defaultSize={{
        width: 300,
        height: 300,
      }}
      maxHeight="80vh"
      maxWidth="600"
      minWidth="300"
      minHeight="300"
      enable={{
        top: true,
        right: false,
        bottom: false,
        left: true,
        topRight: false,
        bottomRight: false,
        bottomLeft: false,
        topLeft: true,
      }}
    >
       <FlatList
            data={parsedPacks}
            keyExtractor={(item) => item.packName}
            renderItem={({item}) => (
              <PackListItem
                packName={item.packName || pack}
                content={item.content}
              />
            )}
          />
</Resizable>

React gives typeerror even though i made a if statement for if it is not there?

I am making a basic js cart with local storage by default the cart is set to [].

sometimes my code works if i reload the page sometimes it dosent.

it works when it feels like it the error is from name1 where i find a object label that is the same as my param

    const cart = localStorage.getItem('cart')

    const Label = {
        strw: 'Strawberry',
        choc: 'Chocolate',
        van: 'Vanilla'
    }

    function Addtocart(name:string){
        const cartarry = JSON.parse(cart)
        const name1 = cartarry.find((element:any)=> element.label === name)

        if(name === Label.strw && name1 != undefined || null){
            console.log(name1)
            return console.log(name)
        }else if(name === Label.choc && name1 != undefined || null){
            console.log(name1)
            return console.log(name)
        }else if(name === Label.van && name1 != undefined || null){
            console.log(name1)
            return console.log(name)
        }else{

            const template = {
                label: name,
                quantity: 1
            }

            cartarry.push(template)
            return localStorage.setItem('cart',JSON.stringify(cartarry))
        }
    }

    useEffect(()=>{
        if(!cart){
            localStorage.setItem('cart',JSON.stringify([]))
        }
    },[])

How can I modify my existing weather app?

I would like to modify my weather app which uses OpenWeatherMap API to fetch data of the specific city by taking input of city from users. In modification, I would like to put map on the webpage and by clicking on the desired location it should give weather info of the same place.

I tried using documentation of OpenWeatherMap API to draw it out but couldn’t find much specific.

Getting Request CacheStorage.requestCacheNames failed Error For my Login Page

I am making a login/registration page for Electron js webapp.

I am only using JavaScript, HTML, and CSS and I am using Indexedb to store user credentials in a database.

I can see it successfully saving the username and password in the Developer Tools section under Application in Electron js window but when the user tries to login I am getting this error.

The user is just redirected to a blank page

Request CacheStorage.requestCacheNames failed. {"code":-32602,"message":"Invalid security origin"}"

I tried adding a console.log() to see if the user was successfully logged in but I am not seeing anything on my console either

Here is a link to my code on codepen:
 

Adding a console.log() and alert() to print out the user who is attempting to login.

Sorting Keys and Values of an Object Javascript

How do i sort this object
here is my code

const player = {"Bong":"henry","rj":"ken","Robert":"dj","Brad":"jeff" }
Object.entries(player).sort(([k,v]) => {
    if(k < v){
        return -1
    }
    if(k > v){
        return 1
    }
    return 0
})

my Expected output should be: {“Bong”:”dj”,”Brad”:”henry”,”rj”:”jeff”,”Robert”:”ken”}

my blog writing input is removing last line in react

this is the current state where I have 4 lines and 5th line in current input

and this is my react code


import { FC, useEffect, useState } from "react";

interface BlogWitterProps {}

const BlogWitter: FC<BlogWitterProps> = ({}) => {
  const [markdownContent, setMarkdownContent] = useState("");
  const [currentLine, setCurrentLine] = useState("");

  // on each new line, update the markdown content

  useEffect(() => {
    console.log("markdownContent", markdownContent);
    console.log("currentLine", currentLine);
  }, [currentLine, markdownContent]);

  const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
    if (e.key === "Enter") {
      setMarkdownContent((prev) => {
        return prev + currentLine + "n";
      });
      setCurrentLine("");
    } else if (e.key === "Backspace" && currentLine === "") {
      e.preventDefault();
      setMarkdownContent((prev) => {
        const lines = prev.split("n");
        const lastLine = lines.pop();
        console.log("lines", lines);

        setTimeout(() => {
          // If the last line is not empty, update the current line state
          if (lastLine !== "") {
            setCurrentLine(lastLine + "n");
          } else {
            setCurrentLine("");
          }
        }, 0);

        return lines.join("n");
      });
    }
  };

  return (
    <div className="">
      <div>
        {markdownContent.split("n").map((line, index) => {
          return (
            <div key={index}>
              {line}
              <br />
            </div>
          );
        })}
      </div>
      <input
        value={currentLine}
        onChange={(e) => {
          setCurrentLine(e.target.value);
        }}
        className="w-full resize-none outline-none text-2xl bg-transparent border border-black"
        onKeyDown={handleKeyDown}
      />
    </div>
  );
};

export default BlogWitter;

so if I press backspace and it takes me to last line to edit then press anter again without changing anything it is remove the last line’s new line and gives me this

enter image description here

I am trying to get it to work as in medieum where you can edit each line seperatly

How to change color of individual words in a text editor/ fade them out over time

I am trying to create a text box that allows users to type. As they do, the most recent (last) words will be black and the previous ones fade to white.

Right now, I have a contenteditable with the following code. Whenever there is a change it takes the current text, splits it into words, wraps the last few words in a span with a black text color class and the previous ones in a span with a white text color class (and some fade between colors). It works, but doesn’t allow for new lines nor any formatting (bold/italics/underline). Is there a way to do this that still allows those? I’ve tried looking at other customizable rich text editors like quill but couldn’t figure out how to get the fade effect. I don’t need most of the functionalities of these rich text editors, really only bolding/italics/maybe font size.

editor.setAttribute("data-placeholder", getRandomPlaceholder(placeholderTexts));


// get rid of spell check red squiggles
editor.spellcheck = false;
editor.focus();
editor.blur();

editor.addEventListener('input', () => {
    let words = editor.innerText.split(/s+/);
    let blackWords = words.slice(-3);
    let fadeWords = words.slice(-8, -3);
    let whiteWords = words.slice(0, -8);

    let whiteSpan = document.createElement('span');
    whiteSpan.className = 'white';
    whiteSpan.innerText = whiteWords.join(' ');

    // Create fade spans
    let fadeSpans = fadeWords.map((word, index) => {
        let span = document.createElement('span');
        span.className = `fade-${index + 1}`;
        span.innerText = word;
        return span;
    });

    let blackSpan = document.createElement('span');
    blackSpan.className = 'black';
    blackSpan.innerText = blackWords.join(' ');

    editor.innerHTML = '';

    if (whiteWords.length > 0) {
        editor.appendChild(whiteSpan);
        editor.appendChild(document.createTextNode(' '));
    }

    // Append fade spans
    fadeSpans.forEach((span, index) => {
        editor.appendChild(span);
        if (index < fadeSpans.length - 1) {
            editor.appendChild(document.createTextNode(' '));
        }
    });

    if (fadeWords.length > 0) {
        editor.appendChild(document.createTextNode(' '));
    }

    editor.appendChild(blackSpan);

    // Move cursor to the end
    let range = document.createRange();
    let selection = window.getSelection();
    range.selectNodeContents(editor);
    range.collapse(false);
    selection.removeAllRanges();
    selection.addRange(range);
});