Some effects require cleanup. For example, we might want to add event listeners to some element in the DOM, beyond the JSX in our component. When we add event listeners to the DOM, it is important to remove those event listeners when we are done with them to avoid memory leaks!
Let’s consider the following effect:
useEffect(()=>{ document.addEventListener('keydown', handleKeyPress); // Specify how to clean up after the effect: return () => { document.removeEventListener('keydown', handleKeyPress); }; })
If our effect didn’t return a cleanup function, then a new event listener would be added to the DOM’s document
object every time that our component re-renders. Not only would this cause bugs, but it could cause our application performance to diminish and maybe even crash!
Because effects run after every render and not just once, React calls our cleanup function before each re-render and before unmounting to clean up each effect call.
If our effect returns a function, then the useEffect()
Hook always treats that as a cleanup function. React will call this cleanup function before the component re-renders or unmounts. Since this cleanup function is optional, it is our responsibility to return a cleanup function from our effect when our effect code could create memory leaks.
Instructions
Let’s practice by making a program that documents how many times you’ve clicked on the page.
Write an event handler named increment()
— It’s responsible for tracking how many times you’ve clicked— define this function so that it calls setClickCount()
with a state setter callback function, adding 1
to the previous value of clickCount
.
Import the useEffect()
hook and call it with an effect that adds an event listener for 'mousedown'
events on the document
object. When a "mousedown"
event occurs anywhere on the document
, we want our increment()
event handler to be called.
If you haven’t already, run our code and click around the browser window. What is happening? Why is this happening?
Each time that our component renders, our effect is called, adding another event listener. With just a few clicks and rerenders, we have attached a lot of event listeners to the DOM! We need to clean up after ourselves!
Update our effect so that it returns a cleanup function that will remove our last event listener from the DOM.