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?

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
}

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)} />

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>

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.


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


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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.