Comment accéder aux attributs personnalisés de l'objet événement dans React?

214

React est capable de restituer des attributs personnalisés comme décrit sur http://facebook.github.io/react/docs/jsx-gotchas.html :

Si vous souhaitez utiliser un attribut personnalisé, vous devez le préfixer avec data-.

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

Et c'est une excellente nouvelle, sauf que je ne peux pas trouver un moyen d'y accéder à partir de l'événement, par exemple:

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

L'élément et la data-propriété s'affichent correctement en html. Les propriétés standard comme stylepeuvent être consultées aussi event.target.stylebien. Au lieu de event.targetj'ai essayé:

 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"]

rien de tout cela n'a fonctionné.

andriy_sof
la source
1
Peut-être qu'un commentaire aide quelqu'un, j'ai découvert que React 16.7 ne restitue pas et met à jour les attributs html personnalisés du composant si vous ne les avez modifiés que dans un magasin (fe redux) et liés au composant. Cela signifie que le composant a fe aria-modal=true, vous poussez les modifications (sur false) dans le magasin d' attributs aria / data , mais rien d'autre n'est modifié (comme le contenu ou la classe du composant ou les variables dedans) car le résultat ReactJs ne mettra pas à jour aria / attrs de données dans ces composants. J'ai déconné toute la journée pour le réaliser.
AlexNikonov

Réponses:

171

Pour vous aider à obtenir le résultat souhaité d'une manière peut-être différente de celle que vous avez demandée:

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

Remarquez le bind(). Parce que tout cela est javascript, vous pouvez faire des choses pratiques comme ça. Nous n'avons plus besoin de joindre des données aux nœuds DOM pour en garder la trace.

OMI, c'est beaucoup plus propre que de compter sur les événements DOM.

Mise à jour d'avril 2017: ces jours-ci, j'écrirais onClick={() => this.removeTag(i)}au lieu de.bind

Jared Forsyth
la source
17
mais vous ne faites plus passer l'événement.
chovy
9
@chovy Veuillez me corriger si je me trompe, mais toutes les fonctions javascript ne sont-elles pas intrinsèquement variées? Je n'ai pas testé cela, mais je suppose que «l'objet événement» est toujours en cours de transmission. Ce n'est PAS au même indice de paramètres qu'auparavant. La liaison de la manière décrite ci-dessus est comme unshiftle tableau d' arguments de fonction . Si l '"objet événement" était à l'index, 0il le serait désormais à l'index 1.
Ryder Brooks
8
@chovy Vous pouvez si vous en avez besoin. Faites justeremoveTag: function(i, evt) {
Jared Forsyth
8
C'est plus propre, mais toutes ces liaisons ont un impact sur les performances si vous en faites beaucoup.
El Yobo
297

event.targetvous donne le nœud DOM natif, vous devez alors utiliser les API DOM normales pour accéder aux attributs. Voici des documents sur la façon de procéder: Utilisation des attributs de données .

Vous pouvez faire soit event.target.dataset.tagou event.target.getAttribute('data-tag'); l'un ou l'autre fonctionne.

Sophie Alpert
la source
24
réagir 0.13.3, IE10 event.target.datasetn'est pas défini mais event.target.getAttribute('data-tag')fonctionne. les autres navigateurs vont bien. Merci
Andrey Borisko
Y a-t-il un problème avec cette approche? Par exemple, en fonction du bouton sur lequel l'utilisateur appuie, je souhaite passer une chaîne à une fonction. J'espérais éviter de faire trois fonctions dans mon composant pour chaque cas.
Michael J.Calkins
4
Cette réponse est meilleure que celle acceptée en termes de performances. Le faire de cette façon signifie que nous ne créons pas de nouvelle fonction sur chaque rendu. Non seulement il saute la création d'une nouvelle fonction à chaque rendu, mais comme la référence de la fonction sera la même à chaque fois, les composants purs (ou mémorisés) ne la verront pas comme une fonction différente. Par conséquent, il ne restituera pas inutilement le composant entier à chaque fois. Même une implémentation personnalisée de shouldComponentUpdateaurait le même problème, sauf si vous avez complètement ignoré la fonction prop.
Michael Yaworski
Fonctionne parfaitement bien
Ogbonna Vitalis
1
J'utilise tapuscrit. Dans mon cas, j'ai dû utiliserevent.currentTarget.getAttibute('data-tag')
karianpour
50

Voici le meilleur moyen que j'ai trouvé:

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

Ces attributs sont stockés dans un "NamedNodeMap", auquel vous pouvez accéder facilement avec la méthode getNamedItem.

roctimo
la source
4
Vous voulez probablement ajouter un .valuepour obtenir la valeur réelle
Wikunia
J'ai modifié la réponse pour ajouter le .valueà la fin comme l'a suggéré
@Wikunia
25

Ou vous pouvez utiliser une fermeture:

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
la source
3
Merci, Tudor. J'ai essayé votre solution et cela fonctionne même sans liaison. Je l'ai utilisé pour basculer les styles sur e.target.
andriy_sof
comment savez-vous qu'une fonction interne contiendra les arguments d'événement?
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
la source
1
ajouter une description à votre code pour faire comprendre le code aux autres
Aniruddha Das
8

Depuis React v16.1.1 (2017), voici la solution officielle: https://reactjs.org/docs/handling-events.html#passing-arguments-to-event-handlers

TLDR: OP devrait faire:

render: function() {
...
<a style={showStyle} onClick={(e) => this.removeTag(i, e)}></a>
...
removeTag: function(i, event) {
    this.setState({inputVal: i}); 
}
tytk
la source
1
D'où vient le «je»?
Freshchris
2
iest l'attribut personnalisé que OP voulait transmettre d'une manière ou d'une autre. C'est une variable qui est dans la portée lorsque l' aélément est défini.
tytk
Ce n'est pas ce que souhaite OP. Ils veulent accéder à une valeur d'attribut sur l'élément (a) avec le gestionnaire onClick.
Design par Adrian
1
Mon point était que la solution officielle est de définir la fonction de gestionnaire d'événements avec la variable dans la portée, plutôt que de définir un attribut de données sur l'élément. Cela ne vous empêche pas d'accéder aux attributs des éléments si vous le voulez vraiment, mais ce n'est pas la façon idiomatique d'accéder à une variable dans React.
tytk
8
<div className='btn' onClick={(e) =>
     console.log(e.currentTarget.attributes['tag'].value)}
     tag='bold'>
    <i className='fa fa-bold' />
</div>

e.currentTarget.attributes['tag'].valuefonctionne donc pour moi

Manindra Gautam
la source
5

Vous pouvez accéder aux attributs de données comme ceci

event.target.dataset.tag
Rameez Iqbal
la source
4

Cette seule ligne de code a résolu le problème pour moi:

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

Je ne connais pas React, mais dans le cas général, vous pouvez passer des attributs personnalisés comme celui-ci:

1) définir à l'intérieur d'une balise html un nouvel attribut avec préfixe de données

data-mydatafield = "asdasdasdaad"

2) Obtenez de javascript avec

e.target.attributes.getNamedItem("data-mydatafield").value 
jimver04
la source
Le mien continue de dire null
Si8
3

Si quelqu'un essaie d'utiliser event.target dans React et trouve une valeur nulle, c'est parce qu'un SyntheticEvent a remplacé event.target. Le SyntheticEvent contient désormais «currentTarget», comme dans event.currentTarget.getAttribute («data-username»).

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

Il semble que React le fasse pour qu'il fonctionne sur plus de navigateurs. Vous pouvez accéder aux anciennes propriétés via un attribut nativeEvent.

Eduardo
la source
3

Essayez au lieu d'attribuer des propriétés dom (ce qui est lent), passez simplement votre valeur en tant que paramètre à la fonction qui crée réellement votre gestionnaire:

render: function() {
...
<a style={showStyle} onClick={this.removeTag(i)}></a>
...
removeTag = (customAttribute) => (event) => {
    this.setState({inputVal: customAttribute});
}
msangel
la source
ressemble à un grand commentaire! comment puis-je voir que l'attribution des propriétés dom est beaucoup plus lente
Ido Bleicher
2

Vous pouvez simplement utiliser l' objet event.target.dataset . Cela vous donnera l'objet avec tous les attributs de données.

Vikash Kumar
la source
0

Dans React vous n'avez pas besoin des données html, utilisez une fonction pour retourner une autre fonction; comme cela, il est très simple d'envoyer des paramètres personnalisés et vous pouvez accéder aux données personnalisées et à l'événement.

render: function() {
...
<a style={showStyle} onClick={this.removeTag(i)}></a>
...
removeTag: (i) => (event) => {
    this.setState({inputVal: i}); 
},
miguel savignano
la source