Reagieren js onClick kann keinen Wert an die Methode übergeben

634

Ich möchte die Eigenschaften des onClick-Ereigniswerts lesen. Aber wenn ich darauf klicke, sehe ich so etwas auf der Konsole:

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

Mein Code funktioniert korrekt. Wenn ich laufe {column}, kann ich es im onClick-Ereignis sehen, aber nicht bekommen.

Mein Code:

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

Wie kann ich onClickin React js einen Wert an das Ereignis übergeben?

user1924375
quelle
2
Mögliches Duplikat der OnClick-Ereignisbindung in React.js
WiredPrairie
2
erwäge stattdessen, dich selbst zu benutzen. Das ist ziemlich irreführend, da es gleichbedeutend mit "dies" sein sollte (nicht wirklich wichtig, für jeden sein eigenes)
Dan
Mit der Bindemethode
Pfeilmethode
1
Schauen Sie

Antworten:

1281

Einfacher Weg

Verwenden Sie eine Pfeilfunktion:

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

Dadurch wird eine neue Funktion erstellt, die aufgerufen wird handleSort mit den richtigen Parametern aufruft.

Besserer Weg

Extrahieren Sie es in eine Unterkomponente. Das Problem bei der Verwendung einer Pfeilfunktion im Renderaufruf besteht darin, dass jedes Mal eine neue Funktion erstellt wird, was zu unnötigen erneuten Rendern führt.

Wenn Sie eine Unterkomponente erstellen, können Sie den Handler übergeben und Requisiten als Argumente verwenden, die dann nur dann neu gerendert werden, wenn sich die Requisiten ändern (da sich die Handlerreferenz jetzt nie ändert):

Unterkomponente

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

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

Hauptbestandteil

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

Alter einfacher Weg (ES5)

Verwenden .bindSie diese Option , um den gewünschten Parameter zu übergeben:

return (
  <th value={column} onClick={that.handleSort.bind(that, column)}>{column}</th>
);
Austin Greco
quelle
7
Reagieren gibt Warnung, wenn ich wie Ihr Code benutze. Ich ändere meinen Code in onClick = {that.onClick.bind (null, column)}
user1924375
12
Wie würden Sie dies mit einem <a>Tag verwenden, an dem Sie das Ereignis bestehen müssen, um es zu verwendenpreventDefault()
Simon H
38
@SimonH Das Ereignis wird als letztes Argument nach den Argumenten übergeben, über die Sie übergeben bind.
Fleck
47
Ist das nicht schlecht für die Leistung? Wird nicht bei jedem Rendern eine neue Funktion erstellt?
Andrew McLagan
13
@ AndrewMcLagan Es ist. Ich fand dies , um die Regel und die performanteste Lösung zu beschreiben.
E. Sundin
140

Hier gibt es nette Antworten, und ich stimme @Austin Greco zu (die zweite Option mit separaten Komponenten).
Es gibt eine andere Art, die ich mag, Curry .
Sie können eine Funktion erstellen, die einen Parameter (Ihren Parameter) akzeptiert und eine andere Funktion zurückgibt, die einen anderen Parameter akzeptiert (in diesem Fall das Klickereignis). dann können Sie damit machen, was immer Sie wollen.

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

Und Sie werden es so verwenden:

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

Hier ist ein vollständiges Beispiel für eine solche Verwendung:

Beachten Sie, dass dieser Ansatz nicht die Erstellung einer neuen Instanz bei jedem Rendering löst.
Ich mag diesen Ansatz gegenüber den anderen Inline-Handlern, da dieser meiner Meinung nach prägnanter und lesbarer ist.

Bearbeiten:
Wie in den Kommentaren unten vorgeschlagen, können Sie das Ergebnis der Funktion zwischenspeichern / auswendig lernen.

Hier ist eine naive Implementierung:

Sagiv bg
quelle
12
Dies sollte die akzeptierte Antwort sein. WIRKLICH einfach zu implementieren und Sie müssen keine anderen Komponenten erstellen oder anders binden. Vielen Dank!
Tamb
29
Sieht besser aus, aber aus Sicht der Leistung hilft Currying nicht wirklich, denn wenn Sie handleChange zweimal mit demselben Parameter aufrufen, erhalten Sie zwei Funktionen, die die JS-Engine als separate Objekte betrachtet, selbst wenn sie dasselbe tun . Sie erhalten also immer noch ein Re-Rendering. Aus Gründen der Leistung müssten Sie die Ergebnisse von handleChange zwischenspeichern, um den Leistungsvorteil zu erzielen. LikehandleChange = param => cache[param] || (e => { // the function body })
travellingprog
6
Dies ist die perfekte Antwort, wenn Sie den Rat von @travellingprog
llioor
2
Kann jemand einen Link bereitstellen oder erklären, wie dieser Caching-Mechanismus funktioniert? Vielen Dank.
Sadok Mtir
2
Schön und ordentlich!
Hatem Alimam
117

Heutzutage könnten wir mit ES6 eine aktualisierte Antwort verwenden.

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

Grundsätzlich onClickfunktioniert (für alle, die es nicht wissen), da erwartet wird, dass eine Funktion an sie übergeben wird, bindweil es eine Kopie einer Funktion erstellt. Stattdessen können wir einen Pfeilfunktionsausdruck übergeben, der einfach die gewünschte Funktion aufruft und beibehält this. Sie sollten die renderMethode niemals in React binden müssen , aber wenn Sie aus irgendeinem Grund thiseine Ihrer Komponentenmethoden verlieren :

constructor(props) {
  super(props);
  this.myMethod = this.myMethod.bind(this);
}
aikeru
quelle
10
Sie müssen nie binden, render()da es von React aufgerufen wird. Wenn überhaupt, müssen Sie binddie Ereignishandler verwenden, und zwar nur, wenn Sie keine Pfeile verwenden.
Dan Abramov
1
@DanAbramov Ich denke, Sie sind korrekt, aber ich habe es nur für den Fall aufgenommen - aktualisiert mit einem Beispiel, das das verbindliche Rendern nicht implizit fördert.
Aikeru
3
Beachten Sie, dass es auch am besten ist, an propsden Konstruktor zu übergeben super()oder this.propsundefiniert zu sein, was verwirrend werden kann.
Dan Abramov
2
Um was zu erreichen? Sie können einen Handler innerhalb der Funktionskomponente definieren und übergeben. Es wird bei jedem Rendern eine andere Funktion sein. Wenn Sie also mit einem Profiler festgestellt haben, dass es Perfektionsprobleme gibt (und nur, wenn Sie sich tatsächlich sicher sind!), Erwägen Sie stattdessen die Verwendung einer Klasse.
Dan Abramov
1
@ me-me Ja, und wenn Sie sich für hochmodernes JavaScript in Babel entscheiden, sollten Sie einfach Eigenschaften für Ihre Klasse wie deklarieren foo = () => {...}und dann beim Rendern <button onClick={this.foo}...den einzigen Grund angeben, eine Pfeilfunktion einzuschließen, wenn Sie babel auf diese Weise verwenden, IMO, Dies ist der Fall, wenn Sie eine Variable erfassen möchten, die nur im Bereich der render () -Methode vorhanden ist (Ereignisse können einfach weitergegeben werden und gelten nicht).
Aikeru
73

[[h / t an @ E.Sundin für die Verknüpfung in einem Kommentar]

Die Top-Antwort (anonyme Funktionen oder Bindung) funktioniert, ist jedoch nicht die leistungsstärkste, da für jede vom. Generierte Instanz eine Kopie des Ereignishandlers erstellt wird map() Funktion .

Dies ist eine Erklärung für die optimale Vorgehensweise mit dem ESLint-Plugin-React :

Artikellisten

Ein häufiger Anwendungsfall für das Binden beim Rendern ist das Rendern einer Liste, um einen separaten Rückruf pro Listenelement zu erhalten:

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

Ziehen Sie den wiederholten Abschnitt nicht auf diese Weise in eine eigene Komponente:

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

});

Dies beschleunigt das Rendern, da bei jedem Rendern keine neuen Funktionen (durch Bindungsaufrufe) erstellt werden müssen.

Brandon
quelle
Ruft React diese Funktionen mit call / apply unter der Haube auf und vermeidet die interne Verwendung von bind?
Aikeru
1
Gibt es eine Möglichkeit, dies mit einer zustandslosen Komponente zu tun?
Carlos Martinez
2
@CarlosMartinez gutes Auge, ich habe das Beispiel aktualisiert - es sollten in erster Linie zustandslose Funktionskomponenten (SFC) sein. Wenn eine Komponente nie verwendet wird this.state, können Sie sie im Allgemeinen sicher gegen eine SFC austauschen.
Brandon
3
Hmm, ich verstehe nicht, wie das performanter ist? Wird die ListItem-Funktion nicht jedes Mal aufgerufen, und daher wird die _onClick-Funktion bei jedem Rendern erstellt.
Mattias Petter Johansson
1
Ich bin hier weit entfernt von einem Experten, aber so wie ich es verstehe, gibt es im 'richtigen' Muster nur eine Instanz des Handlers und es wird die Requisite für jede Instanz der Komponente übergeben, die sie aufruft. Im Bindungsbeispiel (dh dem 'falschen' Muster) gibt es für jede instanziierte Komponente eine Instanz des Handlers. Es ist eine Art Speicheräquivalent dazu, dieselbe Funktion dreißig Mal zu schreiben, sie einmal zu schreiben und sie bei Bedarf aufzurufen.
Brandon
25

Dies ist mein Ansatz, nicht sicher, wie schlimm es ist, bitte kommentieren

Im anklickbaren Element

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

und dann

handleSort(e){
    this.sortOn(e.currentTarget.getAttribute('data-column'));
}
Santiago Ramirez
quelle
Dies ist ein Ansatz, an den ich gedacht habe. Er fühlt sich etwas hackig an, vermeidet jedoch das Erstellen einer neuen Komponente. Ich bin mir nicht sicher, ob getAttribute perfekter oder schlechter ist als das Ziehen in eine separate Komponente.
Kamranicus
2
Ich denke, es ist eine gute Lösung, weil es sehr einfach ist. Es funktioniert jedoch nur mit Zeichenfolgenwerten. Wenn Sie ein Objekt möchten, funktioniert es nicht.
Stephane L
Für ein Objekt müssten Sie dann tun encodeURIComponent(JSON.stringify(myObj)), um es zu analysieren JSON.parse(decodeURIComponent(myObj)). Bei Funktionen bin ich mir ziemlich sicher, dass dies ohne eval oder neue Funktion () nicht funktioniert. Beides sollte vermieden werden. Aus diesen Gründen verwende ich keine Datenattribute, um Daten in React / JS zu übergeben.
Solvitieg
Ich möchte hinzufügen, dass ich dies nicht oft und nur für kleinere Dinge benutze. Aber normalerweise erstelle ich einfach eine Komponente und übergebe die Daten als Requisiten an sie. Behandeln Sie dann entweder den Klick innerhalb dieser neuen Komponente oder übergeben Sie eine onClick-Funktion an die Komponente. Wie in Brandon Antwort erklärt
Santiago Ramirez
1
Auf den Datensatz kann in modernen Browsern (einschließlich IE11) direkt auf diese Weise zugegriffen werden: e.currentTarget.dataset.column
gsziszi
17

Dieses Beispiel unterscheidet sich möglicherweise kaum von Ihrem. Aber ich kann Ihnen versichern, dass dies die beste Lösung für dieses Problem ist. Ich habe tagelang nach einer Lösung gesucht, die keine Leistungsprobleme aufweist. und kam schließlich mit diesem.

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

AKTUALISIEREN

falls Sie sich mit Objekten befassen möchten, die die Parameter sein sollen. Sie können JSON.stringify(object)es in eine Zeichenfolge konvertieren und dem Datensatz hinzufügen.

return (
   <div>
     <h3 data-param={JSON.stringify({name:'me'})} onClick={this.handleClick}>
        {this.state.name}
     </h3>
   </div>
);
hannad rehman
quelle
1
Dies funktioniert nicht, wenn die übergebenen Daten ein Objekt sind
SlimSim
Verwenden Sie JSON.stringify, um das Problem zu beheben. @SlimSim. das sollte den trick machen
hannad rehman
Wenn Sie für dieses Problem JSON.stringify verwenden müssen, ist dies wahrscheinlich nicht die richtige Methode. Der Prozess der Stringifizierung benötigt viel Speicher.
KFE
In den meisten Fällen übergeben Sie die ID nur als Parameter und erhalten die auf dieser ID basierenden Objektdetails von Ihrem Quellobjekt. und warum und wie braucht es viel Speicher, ich weiß, JSON Stringify ist langsam, aber der Klick Fn ist asynchron und es wird keine oder 0 Auswirkung auf Dom haben, sobald er erstellt wurde
Hannad Rehman
6
class extends React.Component {
    onClickDiv = (column) => {
        // do stuff
    }
    render() {
        return <div onClick={() => this.onClickDiv('123')} />
    }
}
Vladimirs Matusevics
quelle
2
Das gleiche - neues DOM bei jedem Rendering. Daher aktualisiert React jedes Mal das DOM.
Alex Shwarc
4

Eine weitere Option, an der .bindES6 nicht beteiligt ist, besteht darin, eine untergeordnete Komponente mit einem Handler zu verwenden, um den übergeordneten Handler mit den erforderlichen Requisiten aufzurufen. Hier ist ein Beispiel (und ein Link zum Arbeitsbeispiel ist unten):

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

Die Grundidee besteht darin, dass die übergeordnete Komponente die onClickFunktion an eine untergeordnete Komponente übergibt. Die untergeordnete Komponente ruft die onClickFunktion auf und kann auf alle propsübergebenen Komponenten (und die event) zugreifen , sodass Sie einen beliebigen eventWert oder andere Requisiten innerhalb der übergeordneten onClickFunktion verwenden können.

Hier ist eine CodePen-Demo, die diese Methode in Aktion zeigt.

Brett DeWoody
quelle
4

Mir ist klar, dass dies für die Party ziemlich spät ist, aber ich denke, eine viel einfachere Lösung könnte viele Anwendungsfälle befriedigen:

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

    ...

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

Ich nehme an, Sie könnten auch eine verwenden data- Attribut verwenden.

Einfach, semantisch.

jhchnc
quelle
4

Erstellen Sie einfach eine solche Funktion

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

und nennen Sie es an der Stelle, die Sie brauchen

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

Charith Jayasanka
quelle
3

Versuchen Sie alternativ, die Frage von OP zu beantworten, einschließlich der Aufrufe von e.preventDefault ():

Gerenderter Link ( ES6 )

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

Komponentenfunktion

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

Sie können es einfach tun, wenn Sie verwenden 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>
     );
   }
 }
Louis Alonzo
quelle
3

Implementieren von show total count von einem Objekt durch Übergeben von count als Parameter von Haupt- an Unterkomponenten, wie unten beschrieben.

Hier ist 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;

Und hier ist 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>
    )
  }
};

Wenn Sie versuchen, oben zu implementieren, erhalten Sie ein genaues Szenario, wie Passparameter in Reactjs auf einer beliebigen DOM-Methode funktionieren.

Nandu
quelle
3

Ich habe eine Wrapper-Komponente geschrieben, die für diesen Zweck wiederverwendet werden kann und auf den hier akzeptierten Antworten aufbaut. Wenn Sie jedoch nur eine Zeichenfolge übergeben müssen, fügen Sie einfach ein Datenattribut hinzu und lesen Sie es aus e.target.dataset (wie einige andere vorgeschlagen haben). Standardmäßig bindet mein Wrapper an alle Requisiten, die eine Funktion sind, und beginnt mit 'on'. Die Daten-Requisiten werden nach allen anderen Ereignisargumenten automatisch an den Aufrufer zurückgegeben. Obwohl ich es nicht auf Leistung getestet habe, haben Sie die Möglichkeit, die Klasse nicht selbst zu erstellen, und es kann folgendermaßen verwendet werden:

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

oder für Komponenten und Funktionen

const DataInput = withData(SomeComponent);

oder wenn Sie es vorziehen

const DataButton = withData(<button/>)

erklären, dass außerhalb Ihres Containers (in der Nähe Ihrer Importe)

Hier ist die Verwendung in einem Container:

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

Hier ist der Wrapper-Code '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;
    }, {});
}
SlimSim
quelle
2

Ich habe unter 3 Vorschläge dazu auf JSX onClick Events -

  1. Tatsächlich müssen wir in unserem Code keine .bind () - oder Arrow-Funktion verwenden. Sie können einfach in Ihrem Code verwenden.

  2. Sie können das Ereignis onClick auch von th (oder ul) nach tr (oder li) verschieben, um die Leistung zu verbessern. Grundsätzlich haben Sie n Anzahl von "Event Listenern" für Ihr n li Element.

    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>

    // Und Sie können item.idin der onItemClickMethode wie unten gezeigt zugreifen :

    onItemClick = (event) => {
       console.log(e.target.getAttribute("item.id"));
    }
  3. Ich stimme dem oben erwähnten Ansatz zum Erstellen einer separaten Reaktionskomponente für ListItem und List zu. Dieser Make-Code sieht jedoch gut aus, wenn Sie 1000 Li haben, werden 1000 Event Listener erstellt. Bitte stellen Sie sicher, dass Sie nicht viel Ereignis-Listener haben sollten.

    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>
            );
        }
    }
Reetesh Agrawal
quelle
1
Dies funktioniert nicht, wenn die Daten, die Sie übergeben müssen, ein Objekt sind. Das Attribut funktioniert nur mit Zeichenfolgen. Auch das Lesen aus dem Dom über das Attribut get ist wahrscheinlich eine teurere Operation.
SlimSim
2

Ich habe der Methode auf zwei Arten Code für die Übergabe des Ereigniswerts onclick hinzugefügt. 1. Verwenden der Bindemethode 2. Verwenden der Pfeilmethode (=>). Siehe die Methoden handleort1 und 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>);
    }
});
Merugu Prashanth
quelle
2

Unten sehen Sie das Beispiel, das den Wert für das onClick-Ereignis übergibt.

Ich habe die es6-Syntax verwendet. Denken Sie daran, dass die Pfeilfunktion in der Klassenkomponente nicht automatisch bindet, daher wird sie im Konstruktor explizit gebunden.

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>
         );
    }
}
Karan Singh
quelle
2

Ich denke, Sie müssen die Methode an die Klasseninstanz von React binden. Es ist sicherer, einen Konstruktor zu verwenden, um alle Methoden in React zu binden. In Ihrem Fall, wenn Sie den Parameter an die Methode übergeben, wird der erste Parameter verwendet, um den 'this'-Kontext der Methode zu binden, sodass Sie nicht auf den Wert innerhalb der Methode zugreifen können.

Andysenclave
quelle
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);
}
Juan David Arce
quelle
2

Es ist ein sehr einfacher Weg.

 onClick={this.toggleStart('xyz')} . 
  toggleStart= (data) => (e) =>{
     console.log('value is'+data);  
 }
Roma Mukherjee
quelle
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>
    );
  }
}
Anik Mazumder
quelle
4
Während dieser Code die Frage lösen kann, hilft das Hinzufügen einer Erklärung wirklich, die Qualität Ihres Beitrags zu verbessern. Denken Sie daran, dass Sie die Frage für Leser in Zukunft beantworten und diese Personen möglicherweise die Gründe für Ihren Codevorschlag nicht kennen.
Shree
2

Ich komme aus dem Nichts zu dieser Frage, aber ich denke, das .bindwird den Trick machen. Hier finden Sie den Beispielcode.

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

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

Verwenden der Pfeilfunktion:

Sie müssen Stufe 2 installieren:

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; 
SM Chinna
quelle
0

Es gibt drei Möglichkeiten, damit umzugehen: -

  1. Binden Sie die Methode im Konstruktor wie folgt: -

    export class HeaderRows extends Component {
       constructor() {
           super();
           this.handleSort = this.handleSort.bind(this);
       }
    }
  2. Verwenden Sie die Pfeilfunktion beim Erstellen als: -

    handleSort = () => {
        // some text here
    }
  3. Der dritte Weg ist folgender:

    <th value={column} onClick={() => that.handleSort} >{column}</th>
Mansi Teharia
quelle
0

Sie können Ihren Code folgendermaßen verwenden:

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

Hier ist e für ein Ereignisobjekt, wenn Sie Ereignismethoden wie preventDefault()in Ihrer Handle-Funktion verwenden oder einen Zielwert oder einen Namen wie erhalten möchten e.target.name.

Bankim Sutaria
quelle
0

Ich fand die Lösung, param als Attribut eines Tags zu übergeben, ziemlich vernünftig.

Es hat jedoch Einschränkungen:

  • Funktioniert nicht richtig, wenn das Listenelement andere Tags hat (daher kann event.target von den beabsichtigten abweichen).
  • Param kann nur eine Zeichenfolge sein. Erfordert Serialisierung und Deserialisierung.

Deshalb habe ich mir diese Bibliothek ausgedacht : react-event-param

Es:

  • Löst das Problem von Kindern, indem bei Bedarf bei Eltern nach den erforderlichen Attributen gesucht wird
  • Serialisiert und deserialisiert automatisch param
  • Verkapselt die Logik des Einstellens und Erhaltens. Sie müssen sich nicht mit Parameternamen anlegen

Anwendungsbeispiel:

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;
sneas
quelle
0

Es gab viele Überlegungen zur Leistung, alle im luftleeren Raum.
Das Problem mit diesen Handlern ist, dass Sie sie curry müssen, um das Argument, das Sie nicht benennen können, in die Requisiten aufzunehmen.
Dies bedeutet, dass die Komponente für jedes anklickbare Element einen Handler benötigt. Lassen Sie uns zustimmen, dass dies für einige Schaltflächen kein Problem ist, oder?
Das Problem tritt auf, wenn Sie Tabellendaten mit Dutzenden von Spalten und Tausenden von Zeilen verarbeiten. Dort bemerken Sie die Auswirkungen der Erstellung so vieler Handler.

Tatsache ist, ich brauche nur einen.
Ich setze den Handler auf Tabellenebene (oder UL oder OL ...), und wenn der Klick erfolgt, kann ich anhand der seitdem im Ereignisobjekt verfügbaren Daten feststellen, welche Zelle angeklickt wurde:

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

Ich verwende die Tagname-Felder, um zu überprüfen, ob der Klick in einem gültigen Element stattgefunden hat, z. B. um Klicks in den Fußzeilen zu ignorieren.
Der rowIndex und der cellIndex geben die genaue Position der angeklickten Zelle an.
Textinhalt ist der Text der angeklickten Zelle.

Auf diese Weise muss ich die Daten der Zelle nicht an den Handler übergeben, sondern kann sie selbst bedienen.
Wenn ich mehr Daten benötige, Daten, die nicht angezeigt werden sollen, kann ich das Dataset-Attribut oder versteckte Elemente verwenden.
Mit einer einfachen DOM-Navigation ist alles zur Hand.
Dies wird seit jeher in HTML verwendet, da PCs viel einfacher zu blockieren waren.

Juan Lanus
quelle
0

Es gibt verschiedene Möglichkeiten, Parameter in Ereignishandlern zu übergeben. Einige folgen den folgenden.

Mit einer Pfeilfunktion können Sie einen Ereignishandler umschließen und Parameter übergeben:

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

Das obige Beispiel entspricht dem Aufruf .bindoder Sie können bind explizit aufrufen.

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

Abgesehen von diesen beiden Ansätzen können Sie auch Argumente an eine Funktion übergeben, die als Curry-Funktion definiert ist.

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

<button onClick={this.handleClick(id)} />
Umair Ahmed
quelle
-1

Verwenden Sie einen Verschluss , um eine saubere Lösung zu erhalten:

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

handleSort Funktion gibt eine Funktion , die den Wert Spalte bereits festgelegt.

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

Die anonyme Funktion wird mit dem richtigen Wert aufgerufen, wenn der Benutzer auf das th klickt.

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

Romel Gomez
quelle
-2

Einfache Änderung ist erforderlich:

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

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

Al Amin Shaon
quelle