Manipulando eventos
Manipular eventos em elementos React é muito semelhante a manipular eventos em elementos do DOM. Existem algumas diferenças de sintaxe:
- Eventos em React são nomeados usando camelCase ao invés de letras minúsculas.
- Com o JSX você passa uma função como manipulador de eventos ao invés de um texto.
Por exemplo, com HTML:
<button onclick="activateLasers()">
Ativar lasers
</button>
É ligeiramente diferente com React:
<button onClick={activateLasers}> Ativar lasers
</button>
Outra diferença é que você não pode retornar false
para evitar o comportamento padrão no React. Você deve chamar preventDefault
explícitamente. Por exemplo, com HTML simples, para evitar o comportamento padrão do formulário de envio, você pode escrever:
<form onsubmit="console.log('Você clicou em enviar.'); return false">
<button type="submit">Enviar</button>
</form>
No React, isso poderia ser:
function Form() {
function handleSubmit(e) {
e.preventDefault(); console.log('Você clicou em enviar.');
}
return (
<form onSubmit={handleSubmit}>
<button type="submit">Enviar</button>
</form>
);
}
Aqui, ”e
” é um synthetic event. O React define esses eventos sintéticos de acordo com a especificação W3C. Então, não precisamos nos preocupar com a compatibilidade entre navegadores. Os eventos React não funcionam exatamente da mesma forma que os eventos nativos. Veja a página SyntheticEvent
para saber mais.
Ao usar o React, geralmente você não precisa chamar addEventListener
para adicionar ouvintes a um elemento no DOM depois que ele é criado. Ao invés disso você pode apenas definir um ouvinte quando o elemento é inicialmente renderizado.
Quando você define um componente usando uma classe do ES6, um padrão comum é que um manipulador de eventos seja um método na classe. Por exemplo, este componente Toggle
renderiza um botão que permite ao usuário alternar entre os estados “ON” e “OFF”:
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = { isToggleOn: true };
// Aqui utilizamos o `bind` para que o `this` funcione dentro da nossa callback this.handleClick = this.handleClick.bind(this); }
handleClick() { this.setState(prevState => ({ isToggleOn: !prevState.isToggleOn })); }
render() {
return (
<button onClick={this.handleClick}> {this.state.isToggleOn ? 'ON' : 'OFF'}
</button>
);
}
}
ReactDOM.render(
<Toggle />,
document.getElementById('root')
);
Você precisa ter cuidado com o significado do this
nos callbacks do JSX. Em JavaScript, os métodos de classe não são vinculados por padrão. Se você esquecer de fazer o bind de this.handleClick
e passá-lo para um onClick
, o this
será undefined
quando a função for realmente chamada.
Este não é um comportamento específico do React. É uma parte de como funcionam as funções em JavaScript. Geralmente, se você referir a um método sem ()
depois dele, como onClick={this.handleClick}
, você deve fazer o bind manual deste método.
Se ficar chamando “bind” incomoda você, há duas maneiras de contornar isso. Se você estiver usando a sintaxe experimental de campos de classe pública, você pode usar campos de classe para vincular callbacks corretamente:
class LoggingButton extends React.Component {
// Essa sintaxe garante que o `this` seja vinculado ao handleClick. // Atenção: essa é uma sintaxe *experimental*. handleClick = () => { console.log('this is:', this); }
render() {
return (
<button onClick={this.handleClick}>
Clique Aqui
</button>
);
}
}
Essa sintaxe é habilitada por padrão no Create React App.
Se você não estiver usando a sintaxe de campos de classe, poderá usar uma arrow function como callback:
class LoggingButton extends React.Component {
handleClick() {
console.log('this is:', this);
}
render() {
// Essa sintaxe garante que o `this` seja vinculado ao handleClick. return ( <button onClick={() => this.handleClick()}> Click me
</button>
);
}
}
O problema com esta sintaxe é que um callback diferente é criado toda vez que o LoggingButton
é renderizado. Na maioria dos casos, tudo bem. No entanto, se esse callback for passado para componentes inferiores através de props, esses componentes poderão fazer uma renderização extra. Geralmente recomendamos a vinculação no construtor ou a sintaxe dos campos de classe para evitar esse tipo de problema de desempenho.
Passando Argumentos para Manipuladores de Eventos
Dentro de uma estrutura de repetição, é comum querer passar um parâmetro extra para um manipulador de evento. Por exemplo, se id
é o ID de identificação da linha, qualquer um dos dois a seguir funcionará:
<button onClick={(e) => this.deleteRow(id, e)}>Deletar linha</button>
<button onClick={this.deleteRow.bind(this, id)}>Deletar linha</button>
As duas linhas acima são equivalentes e usam arrow functions e Function.prototype.bind
respectivamente.
Em ambos os casos, o argumento e
representando o evento do React será passado como segundo argumento após o ID. Com uma arrow function, nós temos que passá-lo explicitamente. Mas com o bind
outros argumentos adicionais serão automaticamente encaminhados.