# React: event handlers and hooks

> How to correctly handle event handlers in React, including events on window like resize and scroll, avoiding the most common mistakes.

- Autore / Author: Diego Betto (https://diegobetto.com/about/)
- Pubblicato / Published: 2024-06-15
- URL: https://diegobetto.com/en/react-event-handler-hooks/
- Tag: react, events, handler, hook, javascript, useEffect

## Preface

When developing with <strong>React</strong>, **events** tied to mouse or keyboard interactions are usually handled directly through component attributes.

Sometimes, though, you need to handle particular events, such as those tied to the `window` object, like `resize` or `scroll`. So let's look at how to handle them correctly.

## Event handlers

We can write classic React <strong>event</strong> handlers.
For example, if we want to handle both the click and double-click events on a `div`, we can write something like this:

```jsx
<div onClick={handleClick} onDoubleClick={(event) => handleDblClick(event)}>
  ...
</div>
```

In the example above we find two event handlers specified in two different ways. Both are valid and behave similarly.

When we specify the handler in the first form, we're saying "when the click event fires, call `handleClick`, passing it all the parameters the `onClick` attribute provides."
In the second form, instead, we're saying to call the `handleDblClick` event handler passing only the `event` parameter.

Good practice is to primarily use component props when writing event handlers.

When instead we write classic JavaScript event handlers, we usually write something like this:

```js
function handleResize() {
  console.log("New dimensions: ", window.innerWidth, "x", window.innerHeight);
}

window.addEventListener("resize", handleResize);
```

In this specific example we first have an <strong>event handler</strong>, i.e. a function to run when a given event fires.
That alone isn't enough, of course. We've only written the function — we still need to specify when it should run. We do that with the last line: we attach an event listener to the `window` object that, on the `resize` event, calls the `handleResize` function, passing it all the available parameters.

> For simplicity, I'm not optimizing the code in these examples. For listeners on events like
> resize, you should add some <strong>debounce</strong> or <strong>throttle</strong> to avoid firing
> the event too many times, slowing down and making the interface less smooth. I wrote a short guide{" "}
> [on how to use debounce and throttle in JavaScript](https://diegobetto.com/debounce-throttle-javascript)

## The problem: we're in a Single Page Application

In <strong>React</strong>, though, we need to pay attention. We're inside a <strong>SPA</strong>, i.e. a <strong>Single Page Application</strong>. We never really _leave_ a page.
The global-level event handlers you register, timers, etc. stay active unless you terminate them yourself.\
The risk, on top of that, is that on every mount of the component you register new, duplicate event handlers.

## Registering the event handler with `useEffect`

We can use the <strong>useEffect</strong> hook to attach the event listener when the component mounts, and then detach it when the component unmounts.
This ensures the code only runs when needed.

The code we can write is as follows:

```js
import { useEffect } from "react";

function handleResize() {
  console.log("New dimensions: ", window.innerWidth, "x", window.innerHeight);
}

export default function App() {
  useEffect(() => {
    window.addEventListener("resize", handleResize);

    return () => {
      window.removeEventListener("resize", handleResize);
    };
  }, []);

  return (
    <div className="App">
      <h1>Your Component</h1>
    </div>
  );
}
```

I declare the `handleResize` function outside the component to avoid it being recreated on every render.
If I had to use hooks, I'd instead be forced to create it internally, possibly optimizing it with a `useCallback` hook.

Inside the component I then use the `useEffect` hook with no dependencies (notice `[]` as the last parameter) so the code only runs on mount, i.e. when the component is added to the <strong>DOM</strong>.

I then declare a `return` that will only run when the component unmounts. This is called a <strong>cleanup</strong> function.

You can find the example at the following [link](https://codesandbox.io/p/sandbox/event-handler-inside-useeffect-t9qsxz?file=%2Fsrc%2FApp.js%3A17%2C1).

## Conclusion

As you've seen, we can correctly register event handlers in a React application.
The important thing is to remember to remove them when they're no longer needed, such as when the component unmounts.
It's not the only way to do it, but it's certainly one of the most common.
