React onClick - evento de passagem com parâmetro

99

Sem Parâmetro

function clickMe(e){
  //e is the event
}

<button onClick={this.clickMe}></button>

Com Parâmetro

function clickMe(parameter){
  //how to get the "e" ?
}
<button onClick={() => this.clickMe(someparameter)}></button>

Eu quero pegar o event. Como posso conseguir?

IMOBAMA
fonte

Respostas:

178

Experimente isto:

<button onClick={(e) => {
     this.clickMe(e, someParameter)
}}>Click Me!</button>

E em sua função:

function clickMe(event, someParameter){
     //do with event
}
Jyothi Babu Araja
fonte
3
Isso me deu um erro eslint ( eslint.org/docs/rules/arrow-parens.html ) O que fiz foi colocar os parâmetros da função entre parêntesesonClick={(e) => { this.clickMe(e, someparameter) }}
kretzm
1
Sim @kretzm Se não fornecermos colchetes, ele atua como uma expressão de retorno quando for uma única linha, caso contrário, devemos usar colchetes para quebrar como um corpo de função.
Jyothi Babu Araja
4
Só quero acrescentar que não é uma sintaxe recomendada. Dos documentos reactjs: O problema com essa sintaxe é que um retorno de chamada diferente é criado cada vez que o botão é renderizado. Na maioria dos casos, isso é bom. No entanto, se esse retorno de chamada for passado como um suporte para componentes inferiores, esses componentes podem fazer uma nova renderização extra. Geralmente recomendamos vincular no construtor ou usar a sintaxe dos campos de classe, para evitar esse tipo de problema de desempenho. Mais informações em reactjs.org
northernwind
1
@Vencedor. Sim você está certo. Mas se você quiser o contexto do seu pai dentro do seu retorno de chamada, você precisa ter um retorno de chamada diferente em cada renderização. Na verdade, é uma troca, eu acho.
Jyothi Babu Araja
@JyothiBabuAraja Acho que a melhor solução é utilizar os data-*atributos em HTML5. Por favor, veja minha resposta abaixo para mais detalhes.
Harry Chang de
38

Com o ES6, você pode fazer de forma mais curta, como este:

const clickMe = (parameter) => (event) => {
    // Do something
}

E use-o:

<button onClick={clickMe(someParameter)} />
Minh Kha
fonte
isso também resolve a criação de um novo problema de retorno de chamada? stackoverflow.com/questions/42597602/…
Otani Shuzo
1
além disso, você pode enviar vários parâmetros. const clickMe = (parâmetro1, parâmetro2) => (evento) => {// Faça algo}
AhuraMazda
1
Este também é disparado quando seu componente é montado, seu código deve ser:onClick={(e) => clickMe(someParameter)(e)}
Alexander Kim
Da mesma forma que se apenas clickMe, você também pode destruir o evento, mesmo que você não o defina como um parâmetro.
Minh Kha
Obrigado por isso. Funciona. Mas por que há const clickMe = (parameter) => (event) => {...} em vez const clickMe = (parameter) => {...}?
zrna,
17

Solução 1

function clickMe(parameter, event){
}

<button onClick={(event) => {this.clickMe(someparameter, event)}></button>

Solução 2 O uso da função de vinculação é considerado melhor do que o método da função de seta, na solução 1. Observe que o parâmetro do evento deve ser o último parâmetro na função do manipulador

function clickMe(parameter, event){
}

<button onClick={this.clickMe.bind(this, someParameter)}></button>
Bence Dergez
fonte
1 para o parâmetro de evento sendo a última coisa na solução # 2. Levei uma eternidade para perceber o que estava fazendo de errado, devo ter perdido o motivo em algum lugar dos documentos.
abelito de
5

Para resolver completamente o problema de criação de um novo retorno de chamada, utilizar os data-*atributos em HTML5 é a melhor solução IMO. Pois no final do dia, mesmo que você extraia um subcomponente para passar os parâmetros, ele ainda cria novas funções.

Por exemplo,

const handleBtnClick = e => {
  const { id } = JSON.parse(e.target.dataset.onclickparam);
  // ...
};

<button onClick={handleBtnClick} data-onclickparam={JSON.stringify({ id: 0 })}>

Consulte https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes para usar os data-*atributos.

Harry Chang
fonte
Eu gosto dessa abordagem. Simples e limpo
marknt15
5

Currying com ES6 exemplo:

const clickHandler = param => event => {
  console.log(param); // your parameter
  console.log(event.type); // event type, e.g.: click, etc.
};

Nosso botão, que alterna o manipulador:

<button onClick={(e) => clickHandler(1)(e)}>Click me!</button>

Se você quiser chamar esta expressão de função sem um objeto de evento, chame-a desta forma:

clickHandler(1)();

Além disso, como o react usa eventos sintéticos (um wrapper para eventos nativos), existe um pool de eventos , o que significa que, se você quiser usar seu eventobjeto de forma assíncrona, terá que usar event.persist():

const clickHandler = param => event => {
  event.persist();
  console.log(event.target);
  setTimeout(() => console.log(event.target), 1000); // won't be null, otherwise if you haven't used event.persist() it would be null.
};

Aqui está um exemplo ao vivo: https://codesandbox.io/s/compassionate-joliot-4eblc?fontsize=14&hidenavigation=1&theme=dark

Alexander Kim
fonte
Por que ainda preciso ter event.persist()com, console.log(event)mas não preciso com console.log(event.target)?
Isaac Pak
Neste contexto, é mais rápido usar uma função normal recebendo 2 parâmetros do que currying. você pode executar um teste de benchmark em jsben.ch
ncesar de
@ncesar Como você configura o React em jsben.ch? Publique seu teste, plz.
Isaac Pak
@IsaacPak jsben é uma ferramenta simples para testar códigos javascript. Você basicamente coloca dois exemplos diferentes de código e compara sua velocidade. Você não precisa colocar todo o código React, apenas uma função que você acha que pode ser mais lenta e deseja testar. Além disso, sempre uso jsben.ch e jsbench.me apenas para ter certeza. No contexto clickHandler, você precisaria simular alguns códigos. Assim let event;, não vai gerar um erro indefinido.
ncesar de