
React: event handler e gli hook
Come utilizzare gli event handler in React ed evitare errori
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.
:::tip[nota] Per semplicità non ottimizzo il codice negli esempi. Nel caso di listener su eventi come resize si dovrebbe aggiungere del debounce o del throttle per evitare che l’evento sia scatenato troppe volte, rallentando e rendendo meno fluida l’interfaccia. Qua ho scritto una breve guida su come usare debounce e throttle in javascript :::
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.