Why do we add eventListeners in useEffect hook

Can anyone please give me a clear explanation on why we add event listeners in useEffect? It always confuses me. I was reading a blog on how to make a navbar fixed on scroll and I saw that the person added the event listener in the useEffect hook. Link to the blog Change Navbar Style With The Scroll In A Next.Js Website

const [clientWindowHeight, setClientWindowHeight] = useState("");

const handleScroll = () => {
     setClientWindowHeight(window.scrollY);
};

useEffect(() => {
    window.addEventListener("scroll", handleScroll); 
    return () => window.removeEventListener("scroll", handleScroll);
});

useEffect tells React to do something (a side effect) after the component has rendered, which is what you want – you have a function that returns some JSX (that is eventually used to create a DOM node). You want to say _“when this function runs, queue up a side effect that manipulates the DOM, using a value defined in the body of my function (clientWindowHeight)”

Edit: if you don’t do that, then you need to remember that the thing you’ve written (a “component”) is just a just a JS function. It runs the code top to bottom and returns the result of that JSX (which is just some function calls). Which means, for one thing, that there is no guarantee that there’s anything rendered on the HTML page at that point

oh seems I get it now. So if I understood it well it means when the page loads initially, the DOM is initially empty until the JSX is used to create the DOM. so if I want to add an event listener to the window or any event listener when the page initially loads, I should rather do that in the useEffect right? so what is the difference between this implementation and something like adding an onClick event unto a button in the jsx?

you can add an event for an element, only once it exists. The useEffect code runs after the element is rendered on the page. If you were to write your element directly in the HTML, you would usually add event handlers to elements inside the ‘DOMcontentLoaded’ event, to make sure they run once the DOM is loaded, unless you already placed your js script in such way, that it loads after the DOM. You cant target and add an event handler to an eleemnt that doesnt even exist.
When you add an event handler inline, like <button onclick={handleClick}/>, it is declared within the render function, so the button will be rendered alongside its functionality.

oh great. Seems I understand it now. Thank you

The other thing I would add is that with useEffect you can make sure to only add the listener once. And to tear it down when the component is unmounted.

1 Like