Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I window removeEventListener using React useEffect

In React Hooks documents it is shown how to removeEventListener during the component's cleanup phase. https://reactjs.org/docs/hooks-reference.html#conditionally-firing-an-effect

In my use case, I am trying to removeEventListener conditional to a state property of the functional component.

Here's an example where the component is never unmounted but the event listener should be removed:

function App () {   const [collapsed, setCollapsed] = React.useState(true);    React.useEffect(     () => {       if (collapsed) {         window.removeEventListener('keyup', handleKeyUp); // Not the same "handleKeyUp" :(       } else {         window.addEventListener('keyup', handleKeyUp);       }     },     [collapsed]   );    function handleKeyUp(event) {     console.log(event.key);     switch (event.key) {       case 'Escape':         setCollapsed(true);         break;     }   }    return collapsed ? (     <a href="javascript:;" onClick={()=>setCollapsed(false)}>Search</a>   ) : (     <span>       <input placeholder="Search" autoFocus />&nbsp;       <a href="javascript:;">This</a>&nbsp;       <a href="javascript:;">That</a>&nbsp;       <input placeholder="Refinement" />     </span>   ); } ReactDOM.render(<App />, document.body.appendChild(document.createElement('div'))); 

(Live sample at https://codepen.io/caqu/pen/xBeBMN)

The problem I see is that the handleKeyUp reference inside removeEventListener is changing every time the component renders. The function handleKeyUp needs a reference to setCollapsed so it must be enclosed by App. Moving handleKeyUp inside useEffect also seems to fire multiple times and lose the reference to the original handleKeyUp.

How can I conditionally window.removeEventListener using React Hooks without unmounting the component?

like image 879
Caqu Avatar asked Mar 26 '19 15:03

Caqu


People also ask

Does useEffect re render?

Inside, useEffect compares the two objects, and since they have a different reference, it once again fetches the users and sets the new user object to the state. The state updates then triggers a re-render in the component.

What is useEffect cleanup?

What is the useEffect cleanup function? Just like the name implies, the useEffect cleanup is a function in the useEffect Hook that allows us to tidy up our code before our component unmounts. When our code runs and reruns for every render, useEffect also cleans up after itself using the cleanup function.

How do you make useEffect only render once?

To run the useEffect hook callback only once when the component mounts, we just have to pass in an empty array into the 2nd argument of useEffect hook. We just pass in an empty array into useEffect and the callback would only run once.


1 Answers

You can put the handleKeyUp function inside of the function given to useEffect (which is the recommended way of doing it according to the official documentation) and only add the listener and return a cleanup function when collapsed is false.

useEffect(() => {   if (collapsed) {     return;   }    function handleKeyUp(event) {     switch (event.key) {       case "Escape":         setCollapsed(true);         break;     }   }    window.addEventListener("keyup", handleKeyUp);   return () => window.removeEventListener("keyup", handleKeyUp); }, [collapsed]); 
like image 97
Tholle Avatar answered Oct 21 '22 17:10

Tholle