Gestione degli Eventi
La gestione degli eventi negli elementi React è molto simile alla gestione degli eventi negli elementi DOM. Vi sono alcune differenze sintattiche:
- Gli eventi React vengono dichiarati utilizzando camelCase, anziché in minuscolo.
- In JSX, il gestore di eventi (event handler) viene passato come funzione, piuttosto che stringa.
Per esempio, l’HTML:
<button onclick="attivaLasers()">
Attiva Lasers
</button>
è leggermente diverso in React:
<button onClick={attivaLasers}> Attiva Lasers
</button>
Un’altra differenza è che, in React, non è possibile ritornare false
per impedire il comportamento predefinito. Devi chiamare preventDefault
esplicitamente. Ad esempio, in un semplice codice HTML per impedire il comportamento predefinito del link di aprire una nuova pagina, potresti scrivere:
<a href="#" onclick="console.log('Hai cliccato sul link.'); return false">
Clicca qui
</a>
In React, invece sarebbe:
function ActionLink() {
function handleClick(e) { e.preventDefault(); console.log('Hai cliccato sul link.'); }
return (
<a href="#" onClick={handleClick}> Clicca qui
</a>
);
}
In questo esempio, il parametro e
è un evento sintetico (synthetic event). React definisce questi eventi sintetici in base alle specifiche W3C, quindi non hai bisogno di preoccuparti della compatibilità tra browser. Gli eventi React non funzionano esattamente allo stesso modo degli eventi nativi. Consulta la guida di riferimento SyntheticEvent
per saperne di più.
Usando React, in generale, non dovresti aver bisogno di chiamare addEventListener
per aggiungere listeners ad un elemento DOM dopo la sua creazione. Invece, basta fornire un listener quando l’elemento è inizialmente renderizzato.
Quando definisci un componente usando una classe ES6, un pattern comune è usare un metodo della classe come gestore di eventi. Ad esempio, questo componente Interruttore
renderizza un pulsante che consente all’utente di alternare gli stati “Acceso” e “Spento”:
class Interruttore extends React.Component {
constructor(props) {
super(props);
this.state = {acceso: true};
// Necessario per accedere al corretto valore di `this` all'interno della callback this.handleClick = this.handleClick.bind(this); }
handleClick() { this.setState(state => ({ acceso: !state.acceso })); }
render() {
return (
<button onClick={this.handleClick}> {this.state.acceso ? 'Acceso' : 'Spento'}
</button>
);
}
}
ReactDOM.render(
<Interruttore />,
document.getElementById('root')
);
Fai attenzione al valore di this
nelle callback JSX. In JavaScript, i metodi delle classi non sono associati (bound) di default. Se dimentichi di applicare bind
a this.handleClick
e di passarlo a onClick
, this
sarà undefined
quando la funzione verrà effettivamente chiamata.
Questo non è un comportamento specifico in React: è parte di come funzionano le funzioni in JavaScript. In generale, se ti riferisci ad un metodo senza ()
dopo di esso, per esempio onClick = {this.handleClick}
, potresti aver bisogno di applicare bind
a quel metodo.
Se usare la chiamata al metodo bind
ti sembra troppo, ci sono due alternative a disposizione. Puoi usare la sintassi sperimentale proprietà pubbliche delle classi, utilizzando le proprietà delle classi per associare correttamente le callback:
class LoggingButton extends React.Component {
// Garantisce che `this` si riferisca all'oggetto originale all'interno di handleClick. // Attenzione: questa è sintassi *sperimentale*. handleClick = () => { console.log('Il valore di `this` è: ', this); }
render() {
return (
<button onClick={this.handleClick}>
Clicca qui
</button>
);
}
}
Questa sintassi è abilitata nelle impostazioni predefinite di Create React App.
Se non stai usando la sintassi delle proprietà delle classi, è possibile utilizzare una funzione a freccia all’interno della callback:
class LoggingButton extends React.Component {
handleClick() {
console.log('Il valore di `this` è: ', this);
}
render() {
// Questa sintassi garantisce che `this` sia associato correttamente all'interno di handleClick return ( <button onClick={() => this.handleClick()}> Clicca qui
</button>
);
}
}
Il problema con questa sintassi è che viene creata una callback diversa ogni volta che LoggingButton
viene renderizzato. Nella maggior parte dei casi, non vi sono problemi. Tuttavia, se questa callback viene passata come prop a componenti inferiori, tali componenti potrebbero eseguire un ulteriore re-renderizzamento. In generale, vi consigliamo di utilizzare bind
nel costruttore o la sintassi delle proprietà pubbliche nelle classi, per evitare questo tipo di problema di prestazioni.
Passare Argomenti ai Gestori di Eventi
All’interno di un ciclo, è comune avere l’esigenza di passare un parametro aggiuntivo ad un gestore di eventi. Ad esempio, avendo id
come l’identificativo della riga, le seguenti dichiarazioni sarebbero entrambe valide:
<button onClick={(e) => this.deleteRow(id, e)}>Elimina riga</button>
<button onClick={this.deleteRow.bind(this, id)}>Elimina riga</button>
Le due linee di codice precedenti sono equivalenti e utilizzano le funzioni a freccia e Function.prototype.bind
rispettivamente.
In entrambi i casi, l’argomento e
, che rappresenta l’evento React, verrà passato come secondo argomento dopo l’ID. Con la funzione a freccia, devi passarlo esplicitamente, mentre con bind
qualsiasi altro argomento viene passato automaticamente.