0

In a functional React component, I'm trying to do a fairly simple operation-

const TestClass = ({lastIndex}) => {
const [activeIndex, setActiveIndex] = useState(0);
const [fullScreenGallery, setFullScreenGallery] = useState(false);

const handleKeyChange = (e) => {
  switch(e.code) {
    case 'ArrowLeft': 
      if(activeIndex - 1 < 0) return setActiveIndex(lastIndex);
      return setActiveIndex(activeIndex-1);
    case 'ArrowRight':
      if(activeIndex + 1 > lastIndex) return setActiveIndex(0);
      return setActiveIndex(activeIndex+1);
    case 'Escape':
      if(fullScreenGallery) {
        // closeFullScreenGallery();
       return;
      }
    }
  }


useEffect(() => {
  document.addEventListener('keydown', handleKeyChange);
// other event listeners
}, []);

return (
<div>
  // some code
</div>
)
}

Issue is, inside handleKeyChange, the value of activeSlide doesn't change after 1, even when I press the key. Can anyone point-out what I'm doing wrong? Same goes for fullScreenGallery.

If I try to add activeSlide and fullScreenGallery as dependencies in useEffect, my event listener starts getting adding whenever the dependency changes and I end up crashing my page.

This code was part of a class component and I'm trying to convert this class to a functional component. In the class component, useEffect code was written inside componentDidMount.

skyboyer
  • 22,209
  • 7
  • 57
  • 64
preeti
  • 39
  • 4
  • if you add a console.log('hello') statement at the beggining of the handleKeyChange you see it called ? – Raphael PICCOLO Jun 30 '21 at 22:23
  • @RaphaelPICCOLO yes. Code works, only issue is when event listener is attached to the DOM, handleKeyChange has the same values of states throughout, irrespective of the state values being updated. Initially, I fixed my code by using a callback inside setState inside which I had access to prevValue and my code was working until I tried to close the gallery and escape wasn't working because if kept on reading the initial value of fullScreenGallery. – preeti Jun 30 '21 at 22:29
  • I followed this solution https://stackoverflow.com/questions/55565444/how-to-register-event-with-useeffect-hooks until I realised I need to track more than two states! – preeti Jun 30 '21 at 22:30

1 Answers1

0

You need to "watch" for activeIndex changes. by setting [] as you did, your useEffect is only launched once. Therefore your activeIndex varaible which is used inside this function always contains the initial value.

Learn more here. https://fr.reactjs.org/docs/hooks-reference.html#conditionally-firing-an-effect

useEffect(() => {
  document.addEventListener('keydown', handleKeyChange);
// other event listeners
}, [activeIndex]);

you also need to removelisteners now. or you will rapidly become overwhelmed by the increasing number of events.

useEffect(() => {
  document.addEventListener('keydown', handleKeyChange);
  return () => {
    document.removeEventListener('keydown', handleKeyChange);
  }

// other event listeners
}, [activeIndex]);

I'm still not sure if hooks are better than classes.

Raphael PICCOLO
  • 2,095
  • 1
  • 12
  • 18
  • If I add activeIndex to watch for, every time activeIndex changes, a new eventListener gets attached to the DOM. Adding and removing eventListeners won't be an optimised solution for me because this code is part of a very heavy LDP that would definitely impact the performance. – preeti Jun 30 '21 at 22:33
  • I agree on the hooks are not better than classes part!! – preeti Jun 30 '21 at 22:34