React: event handler e gli hook

Foto di roegger from Pixabay

Premessa

Nello svilppo con React solitamente gli eventi legati ad interazioni del mouse o della tastiera sono gestiti direttamente utilizzando gli attributi dei componenti.

Capita però a volte di dover gestire eventi particolari ad esempio quelli legati all’oggetto window, come gli eventi di resize o scroll. Vedremo quindi come gestirli in modo corretto.

Gli event handler

Possiamo scrivere dei classici event handler di React. Ad esempio volendo gestire sia l’evento di click che di doppio click su un div possiamo scrivere qualcosa di questo tipo:

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

Nell’esempio di cui sopra troviamo specificati due gestori degli eventi in due modi diversi. Entrambi sono validi e hanno comportamento simile.

Quando specifichiamo l’handler nella prima forma stiamo dicendo “quando si scatena l’evento di click invoca handleClick passandogli come parametri tutti quelli che l’attributo onClick mette a disposizione. Nella seconda forma invece diciamo di invocare l'event handler handleDblClickpassando solo il parametroevent`.

Buona prassi è utilizzare in primis le proprietà dei componenti quando scriviamo degli event handler.

Quando invece sviluppiamo degli event handler classici in JavaScript solitamente scriviamo qualcosa di questo tipo:

function handleResize() {
    console.log('Nuove dimensioni: ', window.innerWidth, 'x', window.innerHeight)
}

window.addEventListener('resize', handleResize)

Nell’esempio specifico prima un event handler, ovvero una fuzione da eseguire quando si scatena un determinato evento. Questo ovviamente non basta. Abbiamo solo scritto la funzione, dobbiamo ancora specificare quando deve essere eseguita. Lo possiamo fare con l’ultima riga: all’oggetto window attacchiamo un event listener che all’evento resize invoca la funzione handleResize passandole tutti i parametri disponibili.

Problema, siamo in una Single Page Application

In React dobbiamo però prestare attenzione. Siamo all’interno di una SPA ovvero una Single Page Application. Non usciamo mai da un pagina veramente. Gli event handler a livello globale che registrate, i timer, ecc rimangono attivi salvo che voi non li terminiate.
Il rischio è oltretutto che ad ogni mount del componente, registriate nuovi event handler copia.

Registriamo l’event handler con useEffect

Possimo usare l’hook useEffect per attivare l’event listener in fase di mount del componente e poi disattivarlo quando il componente stesso viene smontato. Questo ci assicura che il codice viene eseeguito solo quando necessario.

Il codice che possiamo scrivere è come segue:

import { useEffect } from "react";

function handleResize() {
  console.log("Nuove dimensioni: ", 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>
  );
}

Dichiaro la funzione handleResize esternamente al componente per evitare che sia generata ogni volta che viene renderizzato. Se dovessi usare hook invece costretto a crearla internamente, eventualmente ottimizzandola con un hook useCallback.

Nel componente poi uso il l’hook useEffect senza le dipendenze (notate [] come ultimo parametro) per fare in modo che il codice sia eseguito solo in fase di mount, ovvero quando il componente è aggiunto al DOM.

Dichiaro poi un return che verrà eseguito solo in fase di unmount del componente. Questa è una funzione chiamata di cleanup.

Trovate l’esempio al seguente link.

Conclusioni

Come avete visto possiamo correttamente registrare degli event handler in un’applicazione React. L’importante è ricordasi di rimuoverlo quando non più necessario, come ad esempio quando il componente viene smontato. Non è l’unico modo per farlo ma è sicuramente tra i più frequenti.