Wie kann ich über ein Ereignisobjekt in React auf benutzerdefinierte Attribute zugreifen?

214

React kann benutzerdefinierte Attribute rendern, wie unter http://facebook.github.io/react/docs/jsx-gotchas.html beschrieben :

Wenn Sie ein benutzerdefiniertes Attribut verwenden möchten, sollten Sie es mit dem Präfix data- versehen.

<div data-custom-attribute="foo" />

Und das sind großartige Neuigkeiten, außer dass ich keine Möglichkeit finde, über das Ereignisobjekt darauf zuzugreifen, z.

render: function() {
...
<a data-tag={i} style={showStyle} onClick={this.removeTag}></a>
...
removeTag: function(event) {
    this.setState({inputVal: event.target????}); 
},

Das Element und die data-Eigenschaft werden in HTML gut gerendert. Auf Standardeigenschaften wie stylekann als gut zugegriffen werden event.target.style. Stattdessen habe event.targetich versucht:

 event.target.props.data.tag
 event.target.props.data["tag"]
 event.target.props["data-tag"]  
 event.target.data.tag
 event.target.data["tag"]
 event.target["data-tag"]

keines davon funktionierte.

andriy_sof
quelle
1
Vielleicht hilft ein Kommentar jemandem, ich habe herausgefunden, dass React 16.7 die benutzerdefinierten HTML-Attribute der Komponente nicht erneut rendert und aktualisiert, wenn Sie sie nur in einem Geschäft geändert haben (z. B. Redux) und an die Komponente gebunden haben. Dies bedeutet, dass die Komponente zB aria-modal=truehat. Sie verschieben die Änderungen (auf false) in den Speicher der Arien- / Datenattribute, aber nichts anderes wird geändert (wie der Inhalt oder die Klasse oder die Variablen der Komponente), da ReactJs aria / nicht aktualisiert . Daten attrs dass Komponenten. Ich habe den ganzen Tag herumgespielt, um das zu realisieren.
AlexNikonov

Antworten:

171

Um Ihnen zu helfen, das gewünschte Ergebnis auf eine andere Weise als gewünscht zu erzielen:

render: function() {
    ...
    <a data-tag={i} style={showStyle} onClick={this.removeTag.bind(null, i)}></a>
    ...
},
removeTag: function(i) {
    // do whatever
},

Beachten Sie die bind(). Da dies alles Javascript ist, können Sie solche praktischen Dinge tun. Wir müssen keine Daten mehr an DOM-Knoten anhängen, um diese zu verfolgen.

IMO ist dies viel sauberer als sich auf DOM-Ereignisse zu verlassen.

Update April 2017: In diesen Tagen würde ich onClick={() => this.removeTag(i)}statt schreiben.bind

Jared Forsyth
quelle
17
Das Ereignisobjekt wird jedoch nicht mehr übergeben.
Chovy
9
@chovy Bitte korrigieren Sie mich, wenn ich falsch liege, aber nicht alle Javascript-Funktionen von Natur aus variadisch sind. Ich habe dies nicht getestet, aber ich würde annehmen, dass das "Ereignisobjekt" noch übergeben wird. Es ist einfach NICHT auf dem gleichen Parameterindex wie zuvor. Die Bindung in der Art und Weise , wie oben ausgeführt ist wie unshiftdie Funktion ing Argumente Array. Wenn sich das "Ereignisobjekt" im Index befindet, befindet 0es sich jetzt im Index 1.
Ryder Brooks
8
@chovy Sie können, wenn Sie es brauchen. Tun Sie es einfachremoveTag: function(i, evt) {
Jared Forsyth
8
Es ist sauberer, aber all diese Bindungen haben einen Leistungseinbruch, wenn Sie viele davon machen.
El Yobo
296

event.targetWenn Sie den nativen DOM-Knoten erhalten, müssen Sie die regulären DOM-APIs verwenden, um auf Attribute zuzugreifen. Hier finden Sie Dokumente dazu: Verwenden von Datenattributen .

Sie können entweder event.target.dataset.tagoder tun event.target.getAttribute('data-tag'); entweder funktioniert einer.

Sophie Alpert
quelle
24
reagieren 0.13.3, IE10 event.target.datasetist undefiniert, event.target.getAttribute('data-tag')funktioniert aber . Die anderen Browser sind in Ordnung. Vielen Dank
Andrey Borisko
Stimmt etwas mit diesem Ansatz nicht? Abhängig davon, welche Taste der Benutzer drückt, möchte ich beispielsweise eine Zeichenfolge an eine Funktion übergeben. Ich hatte gehofft, nicht drei Funktionen in meiner Komponente für jeden Fall zu machen.
Michael J. Calkins
4
Diese Antwort ist in Bezug auf die Leistung besser als die akzeptierte. Auf diese Weise erstellen wir nicht bei jedem Rendern eine neue Funktion. Es wird nicht nur übersprungen, bei jedem Rendern eine neue Funktion zu erstellen. Da die Funktionsreferenz jedes Mal dieselbe ist, wird sie von reinen (oder gespeicherten) Komponenten nicht als andere Funktion angesehen. Daher wird nicht jedes Mal die gesamte Komponente unnötig neu gerendert. Sogar eine benutzerdefinierte Implementierung von shouldComponentUpdatehätte das gleiche Problem, wenn Sie die Funktionsstütze nicht vollständig ignoriert hätten.
Michael Yaworski
Funktioniert einwandfrei
Ogbonna Vitalis
1
Ich benutze Typoskript. In meinem Fall musste ichevent.currentTarget.getAttibute('data-tag')
karianpour
50

Hier ist der beste Weg, den ich gefunden habe:

var attribute = event.target.attributes.getNamedItem('data-tag').value;

Diese Attribute werden in einer "NamedNodeMap" gespeichert, auf die Sie mit der Methode getNamedItem problemlos zugreifen können.

Roctimo
quelle
4
Sie möchten wahrscheinlich ein hinzufügen .value, um den tatsächlichen Wert zu erhalten
Wikunia
Ich habe die Antwort bearbeitet, um die .valueam Ende hinzuzufügen, wie @Wikunia vorgeschlagen hat
fguillen
25

Oder Sie können einen Verschluss verwenden:

render: function() {
...
<a data-tag={i} style={showStyle} onClick={this.removeTag(i)}></a>
...
},
removeTag: function (i) {
    return function (e) {
    // and you get both `i` and the event `e`
    }.bind(this) //important to bind function 
}
Tudor Campean
quelle
3
Danke, Tudor. Versuchte Ihre Lösung und es funktioniert sogar ohne Bindung. Ich habe es verwendet, um Stile auf e.target umzuschalten.
andriy_sof
Woher wissen Sie, dass eine innere Funktion die Ereignisargumente enthält?
Jack.the.ripper
20
// Method inside the component
userClick(event){
 let tag = event.currentTarget.dataset.tag;
 console.log(tag); // should return Tagvalue
}
// when render element
<a data-tag="TagValue" onClick={this.userClick}>Click me</a>
Mentori
quelle
1
Fügen Sie Ihrem Code eine Beschreibung hinzu, damit andere den Code verstehen
Aniruddha Das
8

Ab React v16.1.1 (2017) ist hier die offizielle Lösung: https://reactjs.org/docs/handling-events.html#passing-arguments-to-event-handlers

TLDR: OP sollte tun:

render: function() {
...
<a style={showStyle} onClick={(e) => this.removeTag(i, e)}></a>
...
removeTag: function(i, event) {
    this.setState({inputVal: i}); 
}
tytk
quelle
1
Woher kommt das Ich?
Freshchris
2
iist das benutzerdefinierte Attribut, das OP irgendwie übergeben wollte. Es ist eine Variable, die im Geltungsbereich liegt, wenn das aElement definiert wird.
Tytk
Das will OP nicht. Sie möchten mit dem onClick-Handler auf einen Attributwert für das Element (a) zugreifen.
Entwurf durch Adrian
1
Mein Punkt war, dass die offizielle Lösung darin besteht, die Event-Handler-Funktion mit der Variablen im Gültigkeitsbereich zu definieren, anstatt ein Datenattribut für das Element festzulegen. Dies hindert Sie nicht daran, auf Attribute von Elementen zuzugreifen, wenn Sie dies wirklich möchten, aber dies ist nicht die idiomatische Möglichkeit, auf eine Variable in React zuzugreifen.
Tytk
8
<div className='btn' onClick={(e) =>
     console.log(e.currentTarget.attributes['tag'].value)}
     tag='bold'>
    <i className='fa fa-bold' />
</div>

so e.currentTarget.attributes['tag'].valuefunktioniert bei mir

Manindra Gautam
quelle
5

Sie können auf Datenattribute wie diese zugreifen

event.target.dataset.tag
Rameez Iqbal
quelle
4

Diese einzelne Codezeile löste das Problem für mich:

event.currentTarget.getAttribute('data-tag')
Emeka Augustine
quelle
3

Ich weiß nicht über React Bescheid, aber im Allgemeinen können Sie benutzerdefinierte Attribute wie folgt übergeben:

1) Definieren Sie in einem HTML-Tag ein neues Attribut mit Datenpräfix

data-mydatafield = "asdasdasdaad"

2) aus Javascript mit bekommen

e.target.attributes.getNamedItem("data-mydatafield").value 
jimver04
quelle
Meins sagt immer wieder null
Si8
3

Wenn jemand versucht, event.target in React zu verwenden und einen Nullwert zu finden, liegt dies daran, dass ein SyntheticEvent das event.target ersetzt hat. Das SyntheticEvent enthält jetzt 'currentTarget', z. B. in event.currentTarget.getAttribute ('data-username').

https://facebook.github.io/react/docs/events.html

Es sieht so aus, als würde React dies tun, damit es in mehr Browsern funktioniert. Sie können über ein nativeEvent-Attribut auf die alten Eigenschaften zugreifen.

Eduardo
quelle
3

Versuchen Sie, anstatt dom-Eigenschaften zuzuweisen (was langsam ist), einfach Ihren Wert als Parameter an eine Funktion zu übergeben, die Ihren Handler tatsächlich erstellt:

render: function() {
...
<a style={showStyle} onClick={this.removeTag(i)}></a>
...
removeTag = (customAttribute) => (event) => {
    this.setState({inputVal: customAttribute});
}
msangel
quelle
sieht aus wie ein toller Kommentar! Wie kann ich sehen, dass es viel langsamer ist, Dom-Eigenschaften
Ido Bleicher
2

Sie können einfach das Objekt event.target.dataset verwenden . Dadurch erhalten Sie das Objekt mit allen Datenattributen.

Vikash Kumar
quelle
0

In React benötigen Sie keine HTML-Daten. Verwenden Sie eine Funktion, um eine andere Funktion zurückzugeben. Auf diese Weise ist es sehr einfach, benutzerdefinierte Parameter zu senden, und Sie können auf die benutzerdefinierten Daten und das Ereignis zugreifen.

render: function() {
...
<a style={showStyle} onClick={this.removeTag(i)}></a>
...
removeTag: (i) => (event) => {
    this.setState({inputVal: i}); 
},
Miguel Savignano
quelle