0

I am working on a magento 2 PWA studio project and a click listener seems to be firing multiple times. I have two languages in website. On the first one, the click listener fires fine. When i switch to the second language, it fires multiple times. Below is the code.

import CmsBlock from '@magento/venia-ui/lib/components/CmsBlock';

const isMobile = useWindowSize().innerWidth < 1024;
const footer = <CmsBlock identifiers="footer" />;

const handleTabClick = useCallback((element) => {
        console.log('handleTabClick')
        element.classList.contains('active-tab') ? element.classList.remove('active-tab') : element.classList.add('active-tab');
    });

useEffect(() => {        
     const buttonElements = document.querySelectorAll('.col-links');
     if (isMobile) {
         buttonElements.forEach(element => {
              element.addEventListener('click', handleTabClick.bind(null, element));
         })
     } else {
         buttonElements.forEach(element => {
              element.classList.contains('active-tab') && element.classList.remove('active-tab');
            })
        }
}, [isMobile, footer, handleTabClick]);

If i return from useEffect and remove the event listener at component un render time,the click listener does not seem to be fired at all when i switch the language. What is wrong with my code?

Note: When language switch happens, the entire website is refreshed.

LosMos
  • 119
  • 9
  • Every time your effect callback runs, you're **adding** event handlers in addition to the ones that were there before (`bind` always returns a new function). You need to remember those old functions and remove them before adding new ones. That said, it's **very** rare to use `addEventListener` in React code. If the elements you're adding the handlers to are rendered by code using React, you should attach the handlers in that code, not after the fact with `addEventListener`. – T.J. Crowder Jun 27 '22 at 12:29
  • @T.J.Crowder The event handler I am adding in react is this way because the component is not created by me in code but, it is the component that is created in PWA studio admin side. So, I cannot directly add event handler like i would do with normal react component. The only option for me is to identify the elements that i need and add event handlers to them once everything is rendered. Also, Could you please elaborate a little? Do u mean that i should remove the bind function first or remove the eventhandler first? I tried removing eventHandler first before adding new evenHandler, same result – LosMos Jun 27 '22 at 13:05
  • You have to remember the functions you're setting as the event handlers (the functions you get from `bind`), probably saving them on a ref, and then the next time the callback runs, you need to remove those with `removeEventHandler` as shown in the linked question's answers before adding the new ones. – T.J. Crowder Jun 27 '22 at 13:14
  • Separately: There's no point to `useCallback` if you don't pass it a dependency array, it will always give you back the new function, since you haven't given it any information to use to memoize and return the earlier function if possible. Looking at your `handleTabClick`, it doesn't seem to use *anything* from state, so you can use an empty deps array to tell `useCallback` you always want it to give you the first function you give it. – T.J. Crowder Jun 27 '22 at 13:15
  • @T.J.Crowder something like this? `buttonElements.forEach(element => { const func = useRef(handleTabClick.bind(null, element)) element.removeEventListener('click', func.current); element.addEventListener('click', func.current); })` – LosMos Jun 27 '22 at 13:23
  • Use a single ref storing an array of functions. You need to ensure that you call `useRef` the same number of times each time your component function runs, and if you do it per element, and the number of elements changes, you'll make a different number of calls to `useRef` and that will throw an error. – T.J. Crowder Jun 27 '22 at 13:27
  • @T.J.Crowder Could you maybe please help me write this in code? I am lost here. Sorry for that but, I am really a beginner in react. – LosMos Jun 27 '22 at 13:31
  • 1
    I was literally just doing that. :-) But I just realized I did something **really** stupid in it, just a sec... (There's no need for a ref.) – T.J. Crowder Jun 27 '22 at 13:34
  • 1
    Okay, the hopefully non-stupid version: https://pastebin.com/b0hw0YtF – T.J. Crowder Jun 27 '22 at 13:41
  • 1
    @T.J.Crowder That works like a fish got into ocean after centuries. I could not have figured it out about bind(). Thank you so much man. Appreciate it. – LosMos Jun 27 '22 at 13:50

0 Answers0