Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot remove an event listener outside useEffect

I add an event listener inside useEffect. It runs once after first rerender due to the useEffect second argument([]). Then I try to remove it outside useEffect (in handleSearch function) but it doesn't work. I suspect it has something to do with function scopes but don't understand it fully. Maybe there is a workaround?

const handleSearch = () => {
  window.removeEventListener('resize', setPageHeightWrapper);
};

const [pageHeight, setPageHeight] = useState(0);

function setPageHeightWrapper() { setPageHeight(window.innerHeight); };
useEffect(() =>{
  window.addEventListener('resize', setPageHeightWrapper);
  return () => {
    window.removeEventListener('resize', setPageHeightWrapper);
  };
}, []);
like image 574
Andrey Lukyanov Avatar asked Feb 07 '19 09:02

Andrey Lukyanov


People also ask

How do you remove event listener in react useEffect?

Add the event listener in the useEffect hook. Return a function from the useEffect hook. Use the removeEventListener method to remove the event listener when the component unmounts.

How do you use cleanup function in useEffect?

The hook comes with a cleanup function, which you might not always need, but it can come in handy. To invoke the cleanup function you can simply add a return function like so: useEffect(() => { // Your effect return () => { // Cleanup }; }, []); The cleanup can prevent memory leaks and remove unwanted things.

When should event listeners be removed?

Since we only need the listener for our modal, it should be removed whenever the user cannot interact with our modal any longer. The same is true for any element that can be toggled as well as animations on elements.

How do I remove all event listeners?

To remove all event listeners from an element: Use the cloneNode() method to clone the element. Replace the original element with the clone. The cloneNode() method copies the node's attributes and their values, but doesn't copy the event listeners.


1 Answers

The reason it doesn't work is because setPageHeightWrapper is defined an inline function and when the component re-renders a new instance of it is created and while clearing an event listener you need to pass the same method which was passed while setting the listener.

On the other hand, when a useEffect hook is called it, gets the function reference from its closure and it uses the same reference to clear the listener.

A way to make the removeListener work outside of useEffect is to use useCallback hook

const handleSearch = () => {
  window.removeEventListener('resize', memoHeightWrapper);
};

const [pageHeight, setPageHeight] = useState(0);


const memoHeightWrapper = useCallback(() => {
    setPageHeight(window.innerHeight);
})
useEffect(() =>{
  window.addEventListener('resize', memoHeightWrapper);
  return () => {
    window.removeEventListener('resize', memoHeightWrapper);
  };
}, []);
like image 197
Shubham Khatri Avatar answered Oct 14 '22 08:10

Shubham Khatri