React js onClick non può passare il valore al metodo


639

Voglio leggere le proprietà del valore dell'evento onClick. Ma quando faccio clic su di esso, vedo qualcosa di simile sulla console:

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

Il mio codice funziona correttamente. Quando corro posso vedere {column}ma non riesco a trovarlo nell'evento onClick.

Il mio codice:

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

Come posso passare un valore onClickall'evento in React js?


2
possibile duplicato dell'associazione OnClick Event in React.js
WiredPrairie,

2
considera l'utilizzo di sé invece di quello. Questo è abbastanza fuorviante in quanto dovrebbe essere sinonimo di "questo" (non molto importante, però, per ognuno il suo)
Dan

Usando il metodo bind e il metodo freccia, possiamo passare il valore all'evento
Onclick

1
Dai

Risposte:


1287

Modo semplice

Utilizzare una funzione freccia:

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

Questo creerà una nuova funzione che chiama handleSortcon i parametri giusti.

Modo migliore

Estrarlo in un sottocomponente. Il problema con l'utilizzo di una funzione freccia nella chiamata di rendering è che creerà una nuova funzione ogni volta, che finirà per provocare il rendering di non necessario.

Se si crea un sottocomponente, è possibile passare il gestore e utilizzare gli oggetti di scena come argomenti, che verranno quindi ri-renderizzati solo quando gli oggetti di scena cambiano (perché il riferimento del gestore ora non cambia mai):

Sottocomponente

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

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

Componente principale

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

Old Easy Way (ES5)

Utilizzare .bindper passare il parametro desiderato:

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

7
reagisce quando avverto come il tuo codice. Cambio il mio codice in onClick = {that.onClick.bind (null, colonna)}
user1924375

12
Come lo useresti con un <a>tag in cui devi passare l'evento, per poter usarepreventDefault()
Simon H

38
@SimonH L'evento verrà passato come ultimo argomento, dopo gli argomenti passati bind.
Macchia il

47
Questo non è male per le prestazioni? non verrà creata una nuova funzione su ogni rendering?
AndrewMcLagan,

13
@AndrewMcLagan Lo è. Ho trovato questo per descrivere la regola e la soluzione più efficace.
E. Sundin,

140

Ci sono belle risposte qui, e sono d'accordo con @Austin Greco (la seconda opzione con componenti separati)
C'è un altro modo che mi piace, il curry .
Quello che puoi fare è creare una funzione che accetta un parametro (il tuo parametro) e restituisce un'altra funzione che accetta un altro parametro (l'evento click in questo caso). allora sei libero di farne ciò che mai vuoi.

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 lo userai in questo modo:

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

Ecco un esempio completo di tale utilizzo:

Si noti che questo approccio non risolve la creazione di una nuova istanza su ciascun rendering.
Mi piace questo approccio rispetto agli altri gestori in linea poiché questo è più conciso e leggibile secondo me.

Modifica:
come suggerito nei commenti seguenti, è possibile memorizzare nella cache / memoize il risultato della funzione.

Ecco un'implementazione ingenua:


12
Questa dovrebbe essere la risposta accettata. REALMENTE facile da implementare e non è necessario creare altri componenti o eseguire il binding in modo diverso. Grazie!
Tamb

29
Sembra migliore, ma dal punto di vista delle prestazioni, il curry non aiuta davvero, perché se si chiama due volte handleChange, con lo stesso parametro, si ottengono due funzioni che il motore JS considera oggetti separati, anche se fanno la stessa cosa . Quindi ottieni ancora un nuovo rendering. Per motivi di prestazioni, è necessario memorizzare nella cache i risultati di handleChange per ottenere il vantaggio prestazionale. Mi piacehandleChange = param => cache[param] || (e => { // the function body })
travellingprog il

6
Questa è la risposta perfetta se rispetti i consigli di @travellingprog
llioor il

2
Qualcuno può fornire un link o spiegare come funziona questo meccanismo di memorizzazione nella cache? Grazie.
Sadok Mtir,

2
Bello e pulito!
Hatem Alimam,

117

Oggi, con ES6, penso che potremmo usare una risposta aggiornata.

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

Fondamentalmente, (per chi non lo sapesse) poiché onClicksi aspetta una funzione passata ad essa, bindfunziona perché crea una copia di una funzione. Invece possiamo passare un'espressione di funzione freccia che invoca semplicemente la funzione che vogliamo e preserva this. Non dovresti mai aver bisogno di associare il rendermetodo in React, ma se per qualche motivo stai perdendo thisin uno dei tuoi metodi componente:

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

10
Non hai mai bisogno di legarti render()perché viene chiamato da React. Semmai, è necessario per bindi gestori di eventi e solo quando non si utilizzano le frecce.
Dan Abramov,

1
@DanAbramov Penso che tu abbia ragione, ma l'ho incluso per ogni evenienza - aggiornato con un esempio che non incoraggia implicitamente il rendering vincolante.
aikeru,

3
Nota è anche migliore di passare propsper super()o this.propssarà indefinito durante il costruttore che può diventare confuso.
Dan Abramov,

2
Per ottenere cosa? È possibile definire un gestore all'interno del componente funzionale e passarlo. Sarà una funzione diversa per ogni rendering, quindi se hai stabilito con un profiler che ti dà problemi perf (e solo se sei davvero sicuro in questo!), Considera invece l'uso di una classe.
Dan Abramov,

1
@ me-me Sì, e se si attiva JavaScript al bleeding edge in Babel, è sufficiente dichiarare le proprietà della propria classe simili foo = () => {...}e quindi fare riferimento a render <button onClick={this.foo}...l'unico motivo per includere una funzione freccia se si utilizza babel in questo modo, IMO, è se vuoi catturare alcune variabili che esistono solo nell'ambito del metodo render () (gli eventi possono essere semplicemente passati e non applicati).
aikeru,

73

[[h / t a @ E.Sundin per averlo collegato in un commento]

La risposta migliore (funzioni anonime o associazione) funzionerà, ma non è la più performante, in quanto crea una copia del gestore eventi per ogni istanza generata dalla map()funzione.

Questa è una spiegazione del modo ottimale per farlo da ESLint-plugin-reazioni :

Elenchi di articoli

Un caso d'uso comune di bind in render è quando si esegue il rendering di un elenco, per avere un callback separato per elemento dell'elenco:

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

Invece di farlo in questo modo, tira la sezione ripetuta nel suo 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>
    );

});

Ciò accelererà il rendering, poiché evita la necessità di creare nuove funzioni (tramite chiamate di bind) su ogni rendering.


La reazione richiama quelle funzioni con call / apply, quindi, sotto il cofano, ed evita di usare il bind internamente?
aikeru,

1
C'è un modo per farlo usando un componente senza stato?
Carlos Martinez,

2
@CarlosMartinez buon occhio, ho aggiornato l'esempio - in primo luogo avrebbero dovuto essere componenti funzionali senza stato (SFC). In genere, se un componente non viene mai utilizzato this.state, è possibile sostituirlo in sicurezza con un SFC.
Brandon,

3
Hmm, non capisco come sia più performante? La funzione ListItem non verrà invocata ogni volta, e quindi la funzione _onClick verrà creata ogni rendering.
Mattias Petter Johansson,

1
Sono tutt'altro che un esperto qui, ma a quanto ho capito, nel modello 'corretto', c'è solo un'istanza del gestore ed è passato il prop per qualunque istanza del componente lo chiama. Nell'esempio di bind (ovvero, il modello "errato"), esiste un'istanza del gestore per ogni componente istanziato. È una specie di equivalente di memoria di scrivere la stessa funzione trenta volte vice scrivendola una volta e chiamandola dove necessario.
Brandon,

25

Questo è il mio approccio, non sono sicuro di quanto sia brutto, per favore commenta

Nell'elemento cliccabile

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

e poi

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

Questo è un approccio a cui stavo pensando, sembra un po 'confuso ma evita di creare un nuovo componente. Non sono sicuro se getAttribute sia migliore o peggiore in termini di perfetti rispetto a un componente separato.
kamranicus,

2
Penso che sia una buona soluzione perché è molto semplice. Funziona solo con valori stringa, se vuoi un oggetto non funziona.
Stephane L

Per un oggetto che avrebbe bisogno di fare encodeURIComponent(JSON.stringify(myObj)), poi analizzarlo, JSON.parse(decodeURIComponent(myObj)). Per le funzioni sono abbastanza sicuro che questo non funzionerà senza valutazione o nuova funzione (), che dovrebbero essere evitati entrambi. Per questi motivi non uso attributi di dati per passare i dati in React / JS.
Solvitieg,

Voglio aggiungere che non lo uso spesso e solo per cose minori. Ma di solito creo solo un componente e gli passo i dati come oggetti di scena. Quindi gestisci il clic all'interno di quel nuovo componente o passa una funzione onClick al componente. Come è spiegato nella risposta di Brandon
Santiago Ramirez,

1
è possibile accedere direttamente al set di dati in questo modo sui browser moderni (incluso IE11): e.currentTarget.dataset.column
gsziszi

17

questo esempio potrebbe essere leggermente diverso dal tuo. ma posso assicurarti che questa è la soluzione migliore che puoi avere per questo problema. ho cercato per giorni una soluzione senza problemi di prestazioni. e finalmente è arrivato questo.

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

AGGIORNARE

nel caso in cui si desideri trattare oggetti che dovrebbero essere i parametri. puoi usarlo JSON.stringify(object)per convertirlo in stringa e aggiungerlo al set di dati.

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

1
questo non funziona quando i dati passati sono un oggetto
SlimSim

utilizzare JSON.stringify per risolvere il problema. @SlimSim. questo dovrebbe fare il trucco
hannad rehman,

Se è necessario utilizzare JSON.stringify per questo problema, probabilmente non è il metodo corretto. Il processo di stringificazione richiede molta memoria.
KFE,

nella maggior parte dei casi passeresti l'ID solo come parametro e otterrai i dettagli dell'oggetto in base a quell'ID dal tuo oggetto di origine. e perché e come ci vuole molta memoria, so che JSON stringify è lento, ma il clic Fn è asincrono e non avrà alcun effetto o 0 su dom, una volta costruito
hannad rehman

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

2
Lo stesso: nuovo DOM su ogni rendering. Quindi React aggiornerà DOM ogni volta.
Alex Shwarc,

4

Un'altra opzione che non prevede .bindo ES6 è quella di utilizzare un componente figlio con un gestore per chiamare il gestore padre con i puntelli necessari. Ecco un esempio (e di seguito un link all'esempio funzionante):

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

L'idea di base è che il componente padre passi la onClickfunzione a un componente figlio. Il componente figlio chiama la onClickfunzione e può accedere a qualsiasi propspassaggio ad essa (e al event), consentendo di utilizzare qualsiasi eventvalore o altri oggetti di scena all'interno della onClickfunzione del genitore .

Ecco una demo di CodePen che mostra questo metodo in azione.


4

Fare un tentativo alternativo per rispondere alla domanda di OP, incluse le chiamate e.preventDefault ():

Link reso ( ES6 )

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

Componente Funzione

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

4

Mi rendo conto che è abbastanza tardi per la festa, ma penso che una soluzione molto più semplice potrebbe soddisfare molti casi d'uso:

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

    ...

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

Suppongo che potresti anche usare un data-attributo.

Semplice, semantico.


4

Basta creare una funzione come questa

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

e chiamalo nel posto che ti serve

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


3

Puoi semplicemente farlo se lo stai utilizzando 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

L'implementazione mostra il conteggio totale da un oggetto passando il conteggio come parametro dai componenti principali a quelli secondari come descritto di seguito.

Ecco 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 qui è 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>
    )
  }
};

Prova a implementare sopra e otterrai lo scenario esatto in cui il funzionamento dei parametri di passaggio nei reagenti su qualsiasi metodo DOM.


3

Ho scritto un componente wrapper che può essere riutilizzato per questo scopo e si basa sulle risposte accettate qui. Se devi solo passare una stringa, aggiungi un attributo di dati e leggilo da e.target.dataset (come alcuni altri hanno suggerito). Per impostazione predefinita, il mio wrapper si legherà a qualsiasi prop che è una funzione e inizia con 'on' e passa automaticamente il prop di dati al chiamante dopo tutti gli altri argomenti dell'evento. Anche se non l'ho testato per le prestazioni, ti darà l'opportunità di evitare di creare tu stesso la classe e può essere usato in questo modo:

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

o per componenti e funzioni

const DataInput = withData(SomeComponent);

o se preferisci

const DataButton = withData(<button/>)

dichiaralo all'esterno del tuo contenitore (vicino alle tue importazioni)

Ecco l'uso in un contenitore:

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

Ecco il codice 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

Ho seguito 3 suggerimenti per questo su JSX onClick Events -

  1. In realtà, non è necessario utilizzare la funzione .bind () o Arrow nel nostro codice. Puoi usare semplicemente il tuo codice.

  2. Puoi anche spostare l'evento onClick da th (o ul) a tr (o li) per migliorare le prestazioni. Fondamentalmente avrai n numero di "Listener di eventi" per il tuo 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 puoi accedere item.idcon il onItemClickmetodo come mostrato di seguito:

    onItemClick = (event) => {
       console.log(e.target.getAttribute("item.id"));
    }
  3. Concordo con l'approccio sopra menzionato per la creazione di un componente React separato per ListItem ed List. Questo codice sembra buono, tuttavia se hai 1000 li, verranno creati 1000 ascoltatori di eventi. Assicurati di non avere molto ascoltatore di eventi.

    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
Questo non funziona quando i dati che devi passare sono un oggetto. L'attributo funzionerà solo con le stringhe. Anche leggere dal dom tramite l'attributo get è probabilmente un'operazione più costosa.
SlimSim

2

Ho aggiunto il codice per passare il valore dell'evento onclick al metodo in due modi. 1 usando il metodo bind 2. usando il metodo arrow (=>). vedere i metodi handleort1 e handleort

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

Di seguito è riportato l'esempio che passa il valore sull'evento onClick.

Ho usato la sintassi es6. ricordare che la funzione della freccia del componente della classe non si associa automaticamente, quindi è esplicitamente vincolante nel costruttore.

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

Immagino che dovrai associare il metodo all'istanza di classe di React. È più sicuro usare un costruttore per associare tutti i metodi in React. Nel tuo caso quando passi il parametro al metodo, il primo parametro viene usato per associare il contesto 'this' del metodo, quindi non puoi accedere al valore all'interno del metodo.


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

C'è un modo molto semplice.

 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
Sebbene questo codice possa risolvere la domanda, inclusa una spiegazione aiuta davvero a migliorare la qualità del tuo post. Ricorda che stai rispondendo alla domanda per i lettori in futuro e che queste persone potrebbero non conoscere i motivi del tuo suggerimento sul codice.
Shree

2

Venendo dal nulla a questa domanda, ma penso .bindche farà il trucco. Trova il codice di esempio qui sotto.

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

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

1

Utilizzando la funzione freccia:

Devi installare stage-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

Ci sono 3 modi per gestirlo: -

  1. Associare il metodo nel costruttore come: -

    export class HeaderRows extends Component {
       constructor() {
           super();
           this.handleSort = this.handleSort.bind(this);
       }
    }
  2. Utilizzare la funzione freccia durante la creazione come: -

    handleSort = () => {
        // some text here
    }
  3. La terza via è questa: -

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

0

Puoi usare il tuo codice in questo modo:

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

Qui è per oggetto evento, se si desidera utilizzare metodi di evento come preventDefault()nella propria funzione handle o si desidera ottenere un valore target o un nome simile e.target.name.


0

Ho trovato abbastanza ragionevole la soluzione di passare param come attributo di un tag.

Tuttavia ha dei limiti:

  • Non funziona correttamente quando l'elemento dell'elenco ha altri tag (quindi event.target potrebbe essere diverso da quello previsto)
  • Param potrebbe essere solo una stringa. Richiede serializzazione e deserializzazione.

Ecco perché mi è venuta in mente questa libreria: React-Event-Param

It:

  • Risolve il problema dei bambini cercando l'attributo necessario nei genitori ogni volta che è necessario
  • Serializza e deserializza automaticamente i parametri
  • Incapsula la logica di impostazione e acquisizione. Non c'è bisogno di pasticciare con i nomi dei parametri

Esempio di utilizzo:

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

C'erano molte considerazioni sulle prestazioni, tutte nel vuoto.
Il problema con questi gestori è che è necessario curry per incorporare l'argomento che non si può nominare negli oggetti di scena.
Ciò significa che il componente necessita di un gestore per ogni elemento selezionabile. Concordiamo sul fatto che per alcuni pulsanti questo non è un problema, giusto?
Il problema sorge quando si gestiscono dati tabulari con dozzine di colonne e migliaia di righe. Lì si nota l'impatto della creazione di così tanti gestori.

Il fatto è che ne ho solo bisogno.
Ho impostato il gestore a livello di tabella (o UL o OL ...) e quando si verifica il clic, posso dire quale era la cella cliccata utilizzando i dati disponibili da sempre nell'oggetto evento:

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

Uso i campi tagname per verificare che il clic sia avvenuto in un elemento valido, ad esempio ignora i clic in TH o piè di pagina.
RowIndex e cellIndex forniscono la posizione esatta della cella selezionata.
Textcontent è il testo della cella selezionata.

In questo modo non ho bisogno di passare i dati della cellula al gestore, può self-service.
Se avessi bisogno di più dati, dati che non devono essere visualizzati, posso usare l'attributo del set di dati o elementi nascosti.
Con una semplice navigazione DOM è tutto a portata di mano.
Questo è stato usato in HTML da sempre, poiché i PC erano molto più facili da impantanare.


0

Esistono due modi per passare i parametri nei gestori di eventi, alcuni sono i seguenti.

È possibile utilizzare una funzione freccia per avvolgere un gestore eventi e passare i parametri:

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

l'esempio sopra è equivalente alla chiamata .bindoppure puoi chiamare esplicitamente il bind.

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

Oltre a questi due approcci, è anche possibile passare argomenti a una funzione definita come funzione curry.

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

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

-1

Utilizzare una chiusura , si traduce in una soluzione pulita:

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

La funzione handleSort restituirà una funzione con la colonna del valore già impostata.

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

La funzione anonima verrà chiamata con il valore corretto quando l'utente fa clic su th.

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


-2

È richiesto un semplice cambio:

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

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.