React js onClick não pode passar valor para o método


639

Eu quero ler as propriedades do valor do evento onClick. Mas quando clico nele, vejo algo assim no console:

SyntheticMouseEvent {dispatchConfig: Object, dispatchMarker: ".1.1.0.2.0.0:1", nativeEvent: MouseEvent, type: "click", target

Meu código está funcionando corretamente. Quando corro, posso ver, {column}mas não consigo, no evento onClick.

Meu código:

var HeaderRows = React.createClass({
  handleSort:  function(value) {
    console.log(value);
  },
  render: function () {
    var that = this;
    return(
      <tr>
        {this.props.defaultColumns.map(function (column) {
          return (
            <th value={column} onClick={that.handleSort} >{column}</th>
          );
        })}
        {this.props.externalColumns.map(function (column) {
          // Multi dimension array - 0 is column name
          var externalColumnName = column[0];
          return ( <th>{externalColumnName}</th>);
        })}
      </tr>
    );
  }
});

Como posso passar um valor para o onClickevento no React js?



2
considere usar o eu em vez disso. Isso é bastante enganosa como deveria ser sinônimo de "isto" (não é importante realmente embora, cada um na sua)
Dan

Usando o método de ligação e flecha método, podemos passar o valor de evento onclick
Merugu Prashanth

Respostas:


1286

Jeito fácil

Use uma função de seta:

return (
  <th value={column} onClick={() => this.handleSort(column)}>{column}</th>
);

Isso criará uma nova função que chama handleSortcom os parâmetros corretos.

Melhor maneira

Extraia-o em um subcomponente. O problema com o uso de uma função de seta na chamada de renderização é que ela criará uma nova função a cada vez, o que acaba causando renderizações desnecessárias.

Se você criar um subcomponente, poderá passar o manipulador e usar props como argumentos, que serão renderizados novamente somente quando os props mudarem (porque a referência do manipulador agora nunca muda):

Subcomponente

class TableHeader extends Component {
  handleClick = () => {
    this.props.onHeaderClick(this.props.value);
  }

  render() {
    return (
      <th onClick={this.handleClick}>
        {this.props.column}
      </th>
    );
  }
}

Componente principal

{this.props.defaultColumns.map((column) => (
  <TableHeader
    value={column}
    onHeaderClick={this.handleSort}
  />
))}

Maneira fácil antiga (ES5)

Use .bindpara passar o parâmetro que você deseja:

return (
  <th value={column} onClick={that.handleSort.bind(that, column)}>{column}</th>
);

7
react dá aviso quando uso como seu código. Eu alterar meu código para onClick = {that.onClick.bind (null, coluna)}
user1924375

12
Como você usaria isso com uma <a>tag na qual precisa passar no evento, a fim de usar #preventDefault()
Simon H #

38
@SimonH O evento será passado como o último argumento, após os argumentos que você passar bind.
mancha

47
Isso não é ruim para o desempenho? uma nova função não será criada em cada renderização?
AndrewMcLagan

13
@AndrewMcLagan It is. Achei isso para descrever a regra e a solução com melhor desempenho.
E. Sundin

140

Há respostas legais aqui, e eu concordo com o Austin Greco (a segunda opção com componentes separados).
Há outra maneira que eu gosto, currying .
O que você pode fazer é criar uma função que aceite um parâmetro (seu parâmetro) e retornar outra função que aceite outro parâmetro (o evento click neste caso). então você é livre para fazer o que quiser.

ES5:

handleChange(param) { // param is the argument you passed to the function
    return function (e) { // e is the event object that returned

    };
}

ES6:

handleChange = param => e => {
    // param is the argument you passed to the function
    // e is the event object that returned
};

E você o usará desta maneira:

<input 
    type="text" 
    onChange={this.handleChange(someParam)} 
/>

Aqui está um exemplo completo desse uso:

Observe que essa abordagem não resolve a criação de uma nova instância em cada renderização.
Eu gosto dessa abordagem em relação aos outros manipuladores embutidos, pois essa é mais concisa e legível na minha opinião.

Editar:
Conforme sugerido nos comentários abaixo, você pode armazenar em cache / memorizar o resultado da função.

Aqui está uma implementação ingênua:


12
Essa deve ser a resposta aceita. REALMENTE fácil de implementar e você não precisa criar outros componentes ou vincular-se de maneira diferente. Obrigado!
Tamb

29
Parece melhor, mas, do ponto de vista do desempenho, o curry não ajuda muito, porque se você chamar handleChange duas vezes, com o mesmo parâmetro, obterá duas funções que o mecanismo JS considera objetos separados, mesmo que façam a mesma coisa . Então você ainda recebe uma nova renderização. Por uma questão de desempenho, você precisaria armazenar em cache os resultados do handleChange para obter a vantagem de desempenho. ComohandleChange = param => cache[param] || (e => { // the function body })
travellingprog

6
Esta é a resposta perfeita se você seguir o conselho de @travellingprog
llioor

2
Alguém pode fornecer um link ou explicar como esse mecanismo de cache funciona? obrigado.
Sadok Mtir

2
Bonito e arrumado!
Hatem Alimam 17/02/2019

117

Atualmente, com o ES6, acho que poderíamos usar uma resposta atualizada.

return (
  <th value={column} onClick={()=>this.handleSort(column)} >{column}</th>
);

Basicamente, (para quem não sabe), pois onClickespera uma função passada para ela, bindfunciona porque cria uma cópia de uma função. Em vez disso, podemos passar uma expressão de função de seta que simplesmente chama a função que queremos e preserva this. Você nunca precisará vincular o rendermétodo no React, mas se por algum motivo estiver perdendo thisem um dos métodos do componente:

constructor(props) {
  super(props);
  this.myMethod = this.myMethod.bind(this);
}

10
Você nunca precisa vincular render()porque é chamado pelo React. Se houver alguma coisa, você precisará binddos manipuladores de eventos e somente quando não estiver usando setas.
21416 Dan Abramov

1
@ DanAbramov Acho que você está correto, mas eu o incluí apenas no caso - atualizado com um exemplo que não incentiva implicitamente a renderização de ligação.
precisa saber é

3
Observe que também é melhor passar propspara super()ou this.propsserá indefinido durante o construtor, o que pode ficar confuso.
Dan Abramov 02/02

2
Para conseguir o que? Você pode definir um manipulador dentro do componente funcional e passá-lo. Será uma função diferente a cada renderização; portanto, se você determinou com um criador de perfil que ele fornece problemas de desempenho (e apenas se você tiver certeza disso!), Considere usar uma classe.
21416 Dan Abramov

1
@ me-me Sim, e se você optar pelo JavaScript de ponta em Babel, deverá declarar propriedades em sua classe como foo = () => {...}e, em seguida, referenciar em renderizar <button onClick={this.foo}...o único motivo para incluir uma função de seta se você usar babel dessa maneira, IMO, é se você deseja capturar alguma variável que só existe no escopo do método render () (os eventos podem ser passados ​​adiante e não se aplicam).
aikeru

73

[[h / t para @ E. Sundin por vincular isso em um comentário]

A resposta principal (funções anônimas ou ligação) funcionará, mas não é a que apresenta melhor desempenho, pois cria uma cópia do manipulador de eventos para todas as instâncias geradas pela map()função.

Esta é uma explicação da maneira ideal de fazê-lo a partir do ESLint-plugin-react :

Listas de itens

Um caso de uso comum de ligação na renderização é ao renderizar uma lista, para ter um retorno de chamada separado por item da lista:

const List = props => (
      <ul>
        {props.items.map(item =>
          <li key={item.id} onClick={() => console.log(item.id)}>
            ...
          </li>
        )}
      </ul>
    );

Em vez de fazer dessa maneira, puxe a seção repetida para seu próprio componente:

const List = props => (
      <ul>
        {props.items.map(item =>
          <ListItem 
            key={item.id} 
            item={item} 
            onItemClick={props.onItemClick} // assume this is passed down to List
           />
        )}
      </ul>
    );


const ListItem = props => {
  const _onClick = () => {
    console.log(props.item.id);
  }
    return (
      <li onClick={_onClick}>
        ...
      </li>
    );

});

Isso acelerará a renderização, pois evita a necessidade de criar novas funções (através de chamadas de ligação) em cada renderização.


Reage invoca essas funções com chamar / aplicar, então, sob o capô, e evita o uso de ligação internamente?
aikeru 12/08

1
Existe uma maneira de fazer isso usando um componente sem estado?
Carlos Martinez

2
@CarlosMartinez bom olho, atualizei o exemplo - eles deveriam ter sido componentes funcionais sem estado (SFC) em primeiro lugar. Geralmente, se um componente nunca for usado this.state, você poderá trocá-lo com segurança por um SFC.
Brandon

3
Hmm, eu não entendo como isso tem mais desempenho? A função ListItem não será chamada toda vez e, portanto, a função _onClick será criada a cada renderização.
Mattias Petter Johansson

1
Estou longe de ser um especialista aqui, mas como eu o entendo, no padrão 'correto', há apenas uma instância do manipulador e ela passou o suporte para qualquer instância do componente que o chama. No exemplo de ligação (ou seja, o padrão 'errado'), há uma instância do manipulador para cada componente instanciado. É o equivalente à memória de escrever a mesma função trinta vezes vice-escrever uma vez e chamá-la quando necessário.
Brandon

25

Esta é a minha abordagem, não tenho certeza do quão ruim é, por favor, comente

No elemento clicável

return (
    <th value={column} onClick={that.handleSort} data-column={column}>   {column}</th>
);

e depois

handleSort(e){
    this.sortOn(e.currentTarget.getAttribute('data-column'));
}

Esta é uma abordagem em que eu estava pensando, parece um pouco hacky, mas evita a criação de um novo componente. Não tenho certeza se getAttribute é melhor ou pior em termos de comparação se comparado a um componente separado.
Kamranicus 15/03

2
Eu acho que é uma boa solução, porque é muito simples. Mas ele funciona apenas com valores de string, se você deseja um objeto, ele não funciona.
Stephane G

Para um objeto que você precisaria fazer encodeURIComponent(JSON.stringify(myObj))e depois analisá-lo JSON.parse(decodeURIComponent(myObj)),. Para funções, tenho certeza de que isso não funcionará sem eval ou nova Function (), as quais devem ser evitadas. Por esses motivos, não uso atributos de dados para transmitir dados no React / JS.
Solvitieg

Quero acrescentar que não uso isso com frequência e apenas para pequenas coisas. Mas geralmente eu apenas crio um componente e passo os dados como acessórios para ele. Em seguida, manipule o clique dentro desse novo componente ou passe uma função onClick para o componente. Como é explicado na resposta de Brandon
Santiago Ramirez

1
conjunto de dados pode ser acessado diretamente por esse caminho em navegadores modernos (incluindo IE11): e.currentTarget.dataset.column
gsziszi

17

este exemplo pode ser um pouco diferente do seu. mas posso garantir que esta é a melhor solução que você pode ter para esse problema. Pesquisei por dias uma solução que não apresentava problemas de desempenho. e finalmente veio com este.

class HtmlComponent extends React.Component {
  constructor() {
    super();
    this.state={
       name:'MrRehman',
    };
    this.handleClick= this.handleClick.bind(this);
  }

  handleClick(event) {
    const { param } = e.target.dataset;
    console.log(param);
    //do what you want to do with the parameter
  }

  render() {
    return (
      <div>
        <h3 data-param="value what you wanted to pass" onClick={this.handleClick}>
          {this.state.name}
        </h3>
      </div>
    );
  }
}

ATUALIZAR

caso você queira lidar com objetos que deveriam ser os parâmetros. você pode usar JSON.stringify(object)para converter em string e adicionar ao conjunto de dados.

return (
   <div>
     <h3 data-param={JSON.stringify({name:'me'})} onClick={this.handleClick}>
        {this.state.name}
     </h3>
   </div>
);

1
isso não funciona quando os dados passados é um objeto
SlimSim

use JSON.stringify para corrigir o problema. @SlimSim. que deve fazer o truque
rehman hannad

Se você precisar usar JSON.stringify para esse problema, provavelmente não é o método correto. O processo de stringificação requer muita memória.
KFE

na maioria dos casos, você passaria o ID apenas como parâmetros e obteria os detalhes do objeto com base nesse ID do seu objeto de origem. e por que e como ele ter um monte de memória, eu sei JSON stringify é lento, mas o clique Fn é assíncrono e não terá nenhum ou 0 efeito sobre dom, uma vez construído
rehman hannad

6
class extends React.Component {
    onClickDiv = (column) => {
        // do stuff
    }
    render() {
        return <div onClick={() => this.onClickDiv('123')} />
    }
}

2
O mesmo - novo DOM em cada renderização. Portanto, o React atualizará o DOM toda vez.
Alex Shwarc

4

Mais uma opção que não envolve .bindou o ES6 é usar um componente filho com um manipulador para chamar o manipulador pai com os acessórios necessários. Aqui está um exemplo (e um link para o exemplo de trabalho está abaixo):

var HeaderRows = React.createClass({
  handleSort:  function(value) {
     console.log(value);
  },
  render: function () {
      var that = this;
      return(
          <tr>
              {this.props.defaultColumns.map(function (column) {
                  return (
                      <TableHeader value={column} onClick={that.handleSort} >
                        {column}
                      </TableHeader>
                  );
              })}
              {this.props.externalColumns.map(function (column) {
                  // Multi dimension array - 0 is column name
                  var externalColumnName = column[0];
                  return ( <th>{externalColumnName}</th>
                  );
              })}
          </tr>);
      )
  }
});

// A child component to pass the props back to the parent handler
var TableHeader = React.createClass({
  propTypes: {
    value: React.PropTypes.string,
    onClick: React.PropTypes.func
  },
  render: function () {
    return (
      <th value={this.props.value} onClick={this._handleClick}
        {this.props.children}
      </th>
    )        
  },
  _handleClick: function () {
    if (this.props.onClick) {
      this.props.onClick(this.props.value);
    }
  }
});

A idéia básica é que o componente pai passe a onClickfunção para um componente filho. O componente filho chama a onClickfunção e pode acessar qualquer um que seja propspassado para ela (e o event), permitindo que você use qualquer eventvalor ou outros acessórios na onClickfunção do pai .

Aqui está uma demonstração do CodePen mostrando esse método em ação.


4

Fazendo uma tentativa alternativa de responder à pergunta do OP, incluindo chamadas e.preventDefault ():

Link renderizado ( ES6 )

<a href="#link" onClick={(e) => this.handleSort(e, 'myParam')}>

Função Componente

handleSort = (e, param) => {
  e.preventDefault();
  console.log('Sorting by: ' + param)
}

4

Sei que é muito tarde para a festa, mas acho que uma solução muito mais simples pode satisfazer muitos casos de uso:

    handleEdit(event) {
        let value = event.target.value;
    }

    ...

    <button
        value={post.id}
        onClick={this.handleEdit} >Edit</button>

Presumo que você também possa usar um data-atributo.

Simples, semântico.


4

Basta criar uma função como esta

  function methodName(params) {
    //the thing  you wanna do
  }

e chame no lugar que você precisa

<Icon onClick = {() => {methodName (theParamsYouwantToPass); }} />


3

Você pode simplesmente fazer isso se estiver usando ES6.

export default class Container extends Component {
  state = {
    data: [
        // ...
    ]
  }

  handleItemChange = (e, data) => {
      // here the data is available 
      // ....
  }
  render () {
     return (
        <div>
        {
           this.state.data.map((item, index) => (
              <div key={index}>
                  <Input onChange={(event) => this.handItemChange(event, 
                         item)} value={item.value}/>
              </div>
           ))
        }
        </div>
     );
   }
 }

3

A implementação mostra a contagem total de um objeto passando a contagem como um parâmetro dos principais para os subcomponentes, conforme descrito abaixo.

Aqui está MainComponent.js

import React, { Component } from "react";

import SubComp from "./subcomponent";

class App extends Component {

  getTotalCount = (count) => {
    this.setState({
      total: this.state.total + count
    })
  };

  state = {
    total: 0
  };

  render() {
    const someData = [
      { name: "one", count: 200 },
      { name: "two", count: 100 },
      { name: "three", count: 50 }
    ];
    return (
      <div className="App">
        {someData.map((nameAndCount, i) => {
          return (
            <SubComp
              getTotal={this.getTotalCount}
              name={nameAndCount.name}
              count={nameAndCount.count}
              key={i}
            />
          );
        })}
        <h1>Total Count: {this.state.total}</h1>
      </div>
    );
  }
}

export default App;

E aqui está SubComp.js

import React, { Component } from 'react';
export default class SubComp extends Component {

  calculateTotal = () =>{
    this.props.getTotal(this.props.count);
  }

  render() {
    return (
      <div>
        <p onClick={this.calculateTotal}> Name: {this.props.name} || Count: {this.props.count}</p>
      </div>
    )
  }
};

Tente implementar acima e você obterá o cenário exato de como os parâmetros de passagem funcionam no reactjs em qualquer método DOM.


3

Escrevi um componente de invólucro que pode ser reutilizado para esse fim com base nas respostas aceitas aqui. Se tudo o que você precisa fazer é passar uma string, adicione um atributo de dados e leia-o em e.target.dataset (como alguns outros sugeriram). Por padrão, meu wrapper se liga a qualquer prop que é uma função e começa com 'on' e passa automaticamente a prop de dados de volta para o chamador, após todos os outros argumentos de evento. Embora eu não o tenha testado quanto ao desempenho, ele lhe dará a oportunidade de evitar a criação da classe e pode ser usado assim:

const DataButton = withData('button')
const DataInput = withData('input');

ou para componentes e funções

const DataInput = withData(SomeComponent);

ou se você preferir

const DataButton = withData(<button/>)

declarar que Fora do contêiner (próximo às importações)

Aqui está o uso em um contêiner:

import withData from './withData';
const DataInput = withData('input');

export default class Container extends Component {
    state = {
         data: [
             // ...
         ]
    }

    handleItemChange = (e, data) => {
        // here the data is available 
        // ....
    }

    render () {
        return (
            <div>
                {
                    this.state.data.map((item, index) => (
                        <div key={index}>
                            <DataInput data={item} onChange={this.handleItemChange} value={item.value}/>
                        </div>
                    ))
                }
            </div>
        );
    }
}

Aqui está o código do wrapper 'withData.js:

import React, { Component } from 'react';

const defaultOptions = {
    events: undefined,
}

export default (Target, options) => {
    Target = React.isValidElement(Target) ? Target.type : Target;
    options = { ...defaultOptions, ...options }

    class WithData extends Component {
        constructor(props, context){
            super(props, context);
            this.handlers = getHandlers(options.events, this);        
        }

        render() {
            const { data, children, ...props } = this.props;
            return <Target {...props} {...this.handlers} >{children}</Target>;
        }

        static displayName = `withData(${Target.displayName || Target.name || 'Component'})`
    }

    return WithData;
}

function getHandlers(events, thisContext) {
    if(!events)
        events = Object.keys(thisContext.props).filter(prop => prop.startsWith('on') && typeof thisContext.props[prop] === 'function')
    else if (typeof events === 'string')
        events = [events];

    return events.reduce((result, eventType) => {
        result[eventType] = (...args) => thisContext.props[eventType](...args, thisContext.props.data);
        return result;
    }, {});
}

2

Tenho abaixo 3 sugestões para isso em JSX onClick Events -

  1. Na verdade, não precisamos usar a função .bind () ou Arrow em nosso código. Você pode usar de maneira simples no seu código.

  2. Você também pode mover o evento onClick de th (ou ul) para tr (ou li) para melhorar o desempenho. Basicamente, você terá n número de "Ouvintes de Eventos" para o seu elemento n li.

    So finally code will look like this:
    <ul onClick={this.onItemClick}>
        {this.props.items.map(item =>
               <li key={item.id} data-itemid={item.id}>
                   ...
               </li>
          )}
    </ul>

    // E você pode acessar item.idno onItemClickmétodo como mostrado abaixo:

    onItemClick = (event) => {
       console.log(e.target.getAttribute("item.id"));
    }
  3. Concordo com a abordagem mencionada acima para criar o React Component separado para ListItem e List. Esse código fica bom, no entanto, se você tiver 1000 li, serão criados 1000 ouvintes de eventos. Certifique-se de que você não deve ter muitos ouvintes de eventos.

    import React from "react";
    import ListItem from "./ListItem";
    export default class List extends React.Component {
    
        /**
        * This List react component is generic component which take props as list of items and also provide onlick
        * callback name handleItemClick
        * @param {String} item - item object passed to caller
        */
        handleItemClick = (item) => {
            if (this.props.onItemClick) {
                this.props.onItemClick(item);
            }
        }
    
        /**
        * render method will take list of items as a props and include ListItem component
        * @returns {string} - return the list of items
        */
        render() {
            return (
                <div>
                  {this.props.items.map(item =>
                      <ListItem key={item.id} item={item} onItemClick={this.handleItemClick}/>
                  )}
                </div>
            );
        }
    
    }
    
    
    import React from "react";
    
    export default class ListItem extends React.Component {
        /**
        * This List react component is generic component which take props as item and also provide onlick
        * callback name handleItemClick
        * @param {String} item - item object passed to caller
        */
        handleItemClick = () => {
            if (this.props.item && this.props.onItemClick) {
                this.props.onItemClick(this.props.item);
            }
        }
        /**
        * render method will take item as a props and print in li
        * @returns {string} - return the list of items
        */
        render() {
            return (
                <li key={this.props.item.id} onClick={this.handleItemClick}>{this.props.item.text}</li>
            );
        }
    }

1
Isso não funciona quando os dados que você precisa passar são um objeto. O atributo funcionará apenas com cadeias. Também a leitura do atributo dom via get provavelmente é uma operação mais cara.
SlimSim

2

Adicionei código para o valor do evento onclick passar para o método de duas maneiras. 1 usando o método de ligação 2. usando o método de seta (=>). veja os métodos HandleSort1 e HandleSort

var HeaderRows  = React.createClass({
    getInitialState : function() {
      return ({
        defaultColumns : ["col1","col2","col2","col3","col4","col5" ],
        externalColumns : ["ecol1","ecol2","ecol2","ecol3","ecol4","ecol5" ],

      })
    },
    handleSort:  function(column,that) {
       console.log(column);
       alert(""+JSON.stringify(column));
    },
    handleSort1:  function(column) {
       console.log(column);
       alert(""+JSON.stringify(column));
    },
    render: function () {
        var that = this;
        return(
        <div>
            <div>Using bind method</div>
            {this.state.defaultColumns.map(function (column) {
                return (
                    <div value={column} style={{height : '40' }}onClick={that.handleSort.bind(that,column)} >{column}</div>
                );
            })}
            <div>Using Arrow method</div>

            {this.state.defaultColumns.map(function (column) {
                return (
                    <div value={column} style={{height : 40}} onClick={() => that.handleSort1(column)} >{column}</div>

                );
            })}
            {this.state.externalColumns.map(function (column) {
                // Multi dimension array - 0 is column name
                var externalColumnName = column;
                return (<div><span>{externalColumnName}</span></div>
                );
            })}

        </div>);
    }
});

2

Abaixo está o exemplo que passa valor no evento onClick.

Eu usei a sintaxe es6. Lembre-se de que a função de seta do componente de classe não se liga automaticamente, portanto se liga explicitamente ao construtor.

class HeaderRows extends React.Component {

    constructor(props) {
        super(props);
        this.handleSort = this.handleSort.bind(this);
    }

    handleSort(value) {
        console.log(value);
    }

    render() {
        return(
            <tr>
                {this.props.defaultColumns.map( (column, index) =>
                    <th value={ column } 
                        key={ index } 
                        onClick={ () => this.handleSort(event.target.value) }>
                        { column }
                    </th>
                )}

                {this.props.externalColumns.map((column, index)  =>
                    <th value ={ column[0] }
                        key={ index }>
                        {column[0]}
                    </th>
                )}
            </tr>
         );
    }
}

2

Eu acho que você precisará vincular o método à instância da classe React. É mais seguro usar um construtor para vincular todos os métodos no React. No seu caso, quando você passa o parâmetro para o método, o primeiro parâmetro é usado para vincular o contexto 'this' do método, portanto, você não pode acessar o valor dentro do método.


2
1. You just have to use an arrow function in the Onclick event like this: 

<th value={column} onClick={() => that.handleSort(theValue)} >{column}</th>

2.Then bind this in the constructor method:
    this.handleSort = this.handleSort.bind(this);

3.And finally get the value in the function:
  handleSort(theValue){
     console.log(theValue);
}

2

Há uma maneira muito fácil.

 onClick={this.toggleStart('xyz')} . 
  toggleStart= (data) => (e) =>{
     console.log('value is'+data);  
 }

2
class TableHeader extends Component {
  handleClick = (parameter,event) => {
console.log(parameter)
console.log(event)

  }

  render() {
    return (
      <button type="button" 
onClick={this.handleClick.bind(this,"dataOne")}>Send</button>
    );
  }
}

4
Embora esse código possa resolver a questão, incluir uma explicação realmente ajuda a melhorar a qualidade da sua postagem. Lembre-se de que você está respondendo à pergunta dos leitores no futuro e essas pessoas podem não saber os motivos da sua sugestão de código.
Shree

2

Saindo do nada para esta pergunta, mas acho que .bindvai fazer o truque. Encontre o código de exemplo abaixo.

const handleClick = (data) => {
    console.log(data)
}

<button onClick={handleClick.bind(null, { title: 'mytitle', id: '12345' })}>Login</button>

1

Usando a função de seta:

Você deve instalar o estágio 2:

npm install babel-preset-stage-2:

class App extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            value=0
        }
    }

    changeValue = (data) => (e) => {
        alert(data);  //10
        this.setState({ [value]: data })
    }

    render() {
        const data = 10;
        return (
            <div>
                <input type="button" onClick={this.changeValue(data)} />
            </div>
        );
    }
}
export default App; 

0

Existem três maneiras de lidar com isso: -

  1. Vincule o método no construtor como: -

    export class HeaderRows extends Component {
       constructor() {
           super();
           this.handleSort = this.handleSort.bind(this);
       }
    }
  2. Use a função de seta enquanto a cria como: -

    handleSort = () => {
        // some text here
    }
  3. A terceira maneira é esta: -

    <th value={column} onClick={() => that.handleSort} >{column}</th>

0

Você pode usar seu código assim:

<th value={column} onClick={(e) => that.handleSort(e, column)} >{column}</th>

Aqui está e para o objeto de evento, se você deseja usar métodos de evento como preventDefault()na função de manipulação ou deseja obter o valor de destino ou nome como e.target.name.


0

Eu achei a solução de passar param como um atributo de tag bastante razoável.

No entanto, possui limitações:

  • Não funciona corretamente quando o item da lista possui outras tags (portanto, event.target pode ser diferente do pretendido)
  • Param poderia ser apenas uma sequência. Requer serialização e desserialização.

Por isso, criei esta biblioteca: react-event-param

Isto:

  • Resolve o problema das crianças, procurando o atributo necessário nos pais sempre que necessário
  • Serializa e desserializa automaticamente os parâmetros
  • Encapsula a lógica de definir e obter. Não há necessidade de mexer com nomes de parâmetros

Exemplo de uso:

import { setEventParam, getEventParam } from "react-event-param";

class List extends Component {
  onItemClick = e => {
    const index = getEventParam(e.target);
    // Do something with index
  };

  render() {
    return (
      <ul>
        {this.props.items.map((itemText, index) => (
          <li
            key={index}
            {...setEventParam(index)}
            onClick={this.onItemClick}
          >
            {{ itemText }}
          </li>
        ))}
      </ul>
    );
  }
}

export default List;

0

Havia muitas considerações de desempenho, todas no vácuo.
O problema com esses manipuladores é que você precisa curry-los para incorporar o argumento que você não pode nomear nos adereços.
Isso significa que o componente precisa de um manipulador para cada elemento clicável. Vamos concordar que, para alguns botões, isso não é um problema, certo?
O problema surge quando você está manipulando dados tabulares com dezenas de colunas e milhares de linhas. Lá você percebe o impacto da criação de muitos manipuladores.

O fato é que eu só preciso de um.
Defino o manipulador no nível da tabela (ou UL ou OL ...) e, quando o clique ocorre, posso dizer qual foi a célula clicada usando os dados disponíveis desde o momento no objeto de evento:

nativeEvent.target.tagName
nativeEvent.target.parentElement.tagName 
nativeEvent.target.parentElement.rowIndex
nativeEvent.target.cellIndex
nativeEvent.target.textContent

Uso os campos tagname para verificar se o clique ocorreu em um elemento válido, por exemplo, ignore cliques em THs ou rodapés.
O rowIndex e cellIndex fornecem o local exato da célula clicada.
Textcontent é o texto da célula clicada.

Dessa forma, não preciso passar os dados da célula para o manipulador, ele pode fazer o autoatendimento.
Se eu precisar de mais dados, dados que não devem ser exibidos, posso usar o atributo do conjunto de dados ou elementos ocultos.
Com alguma navegação DOM simples, está tudo à mão.
Isso tem sido usado em HTML desde sempre, já que os PCs eram muito mais fáceis de entender.


0

Existem algumas maneiras de passar parâmetros nos manipuladores de eventos, alguns estão seguindo.

Você pode usar uma função de seta para contornar um manipulador de eventos e passar parâmetros:

<button onClick={() => this.handleClick(id)} />

O exemplo acima é equivalente a chamar .bindou você pode chamar explicitamente o bind.

<button onClick={this.handleClick.bind(this, id)} />

Além dessas duas abordagens, você também pode passar argumentos para uma função definida como uma função curry.

handleClick = (id) => () => {
    console.log("Hello, your ticket number is", id)
};

<button onClick={this.handleClick(id)} />

-1

Use um fechamento , resultando em uma solução limpa:

<th onClick={this.handleSort(column)} >{column}</th>

A função handleSort retornará uma função que já tenha a coluna de valor definida.

handleSort: function(value) { 
    return () => {
        console.log(value);
    }
}

A função anônima será chamada com o valor correto quando o usuário clicar no th.

Exemplo: https://stackblitz.com/edit/react-pass-parameters-example


-2

Simples alteração é necessária:

Usar <th value={column} onClick={that.handleSort} >{column}</th>

ao invés de <th value={column} onClick={that.handleSort} >{column}</th>

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.