Come accedere agli attributi personalizzati dall'oggetto evento in React?


214

React è in grado di eseguire il rendering di attributi personalizzati come descritto su http://facebook.github.io/react/docs/jsx-gotchas.html :

Se si desidera utilizzare un attributo personalizzato, è necessario aggiungere un prefisso con dati-.

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

E questa è un'ottima notizia tranne che non riesco a trovare un modo per accedervi dall'oggetto evento, ad esempio:

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

L'elemento e la data-proprietà vengono visualizzati in HTML fine. Le proprietà standard come stylesono accessibili come event.target.stylebene. Invece di event.targetaver provato:

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

nessuno di questi ha funzionato.


1
Può essere un commento aiutare qualcuno, ho scoperto che React 16.7 non esegue nuovamente il rendering e aggiorna gli attributi html personalizzati del componente se li hai modificati solo in un negozio (fe redux) e collegati al componente. Questo significa che il componente ha fe aria-modal=true, spingi le modifiche (su false) nel negozio di attributi aria / data , ma non viene cambiato nient'altro (come il contenuto del componente o la classe o le variabili) poiché il risultato ReactJs non aggiornerà aria / i dati attirano quei componenti. Ho fatto casino per tutto il giorno per rendermene conto.
AlexNikonov,

Risposte:


171

Per aiutarti a ottenere il risultato desiderato in un modo forse diverso da quello che hai chiesto:

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

Notare il bind(). Perché questo è tutto javascript, puoi fare cose utili come quelle. Non è più necessario allegare dati ai nodi DOM per tenerne traccia.

IMO questo è molto più pulito che fare affidamento su eventi DOM.

Aggiornamento aprile 2017: Oggi scriverei onClick={() => this.removeTag(i)}invece di.bind


17
ma non si ottiene più l'oggetto evento passato.
amorevole

9
@chovy Per favore, correggimi se sbaglio, ma non tutte le funzioni javascript sono intrinsecamente variabili? Non l'ho provato, ma suppongo che l'oggetto "evento" sia ancora passato. NON si trova nello stesso indice di parametri che era in precedenza. Il legame nel modo descritto sopra è simile all'array degli argomenti delleunshift funzioni . Se l '"oggetto evento" fosse nell'indice ora sarebbe nell'indice . 01
Ryder Brooks,

8
@chovy Puoi farlo se ne hai bisogno. Basta fareremoveTag: function(i, evt) {
Jared Forsyth

8
È più pulito, ma tutti questi vincoli hanno un impatto sulle prestazioni se ne fai molti.
El Yobo,


297

event.targetti dà il nodo DOM nativo, quindi devi usare le normali API DOM per accedere agli attributi. Ecco alcuni documenti su come farlo: Utilizzo degli attributi dei dati .

Puoi fare uno event.target.dataset.tago event.target.getAttribute('data-tag'); uno dei due funziona.


24
reagire 0.13.3, IE10 event.target.datasetnon è definito ma event.target.getAttribute('data-tag')funziona. gli altri browser vanno bene. Grazie
Andrey Borisko il

C'è qualcosa di sbagliato in questo approccio? Ad esempio, a seconda del pulsante premuto dall'utente, voglio passare una stringa a una funzione. Speravo di evitare di fare tre funzioni nel mio componente per ogni caso.
Michael J. Calkins,

4
Questa risposta è migliore di quella accettata in termini di prestazioni. Farlo in questo modo significa che non creiamo una nuova funzione su ogni rendering. Non solo salta la creazione di una nuova funzione per ogni rendering, ma poiché il riferimento alla funzione sarà lo stesso ogni volta, i componenti puri (o memoized) non la vedranno come una funzione diversa. Pertanto, non eseguirà nuovamente il rendering inutilmente dell'intero componente ogni volta. Anche un'implementazione personalizzata di shouldComponentUpdateavrebbe lo stesso problema a meno che tu non abbia ignorato completamente il prop di funzione.
Michael Yaworski

Funziona perfettamente bene
Ogbonna Vitalis

1
Uso il dattiloscritto. Nel mio caso ho dovuto usareevent.currentTarget.getAttibute('data-tag')
karianpour

50

Ecco il modo migliore che ho trovato:

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

Tali attributi sono memorizzati in "NamedNodeMap", a cui è possibile accedere facilmente con il metodo getNamedItem.


4
Probabilmente vuoi aggiungere un .valueper ottenere il valore reale
Wikunia,

Ho modificato la risposta per aggiungere il .valuealla fine come suggerito da
@Wikunia

25

Oppure puoi usare una chiusura:

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 
}

3
Grazie Tudor. Ho provato la tua soluzione e funziona anche senza rilegatura. L'ho usato per attivare e disattivare gli stili su e.target.
andriy_sof

come fai a sapere che una funzione interna conterrà l'evento args?
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>

1
aggiungi una descrizione al tuo codice per far capire ad altri il codice
Aniruddha Das,

8

A partire da React v16.1.1 (2017), ecco la soluzione ufficiale: https://reactjs.org/docs/handling-events.html#passing-arguments-to-event-handlers

TLDR: OP dovrebbe fare:

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

1
Da dove viene l'io?
Freshchris,

2
iè l'attributo personalizzato che OP ha voluto in qualche modo trasmettere. È una variabile che arientra nell'ambito quando l' elemento è definito.
tytk,

Non è quello che vuole OP. Vogliono accedere a un valore di attributo sull'elemento (a) con il gestore onClick.
Design di Adrian,

1
Il mio punto era che la soluzione ufficiale è definire la funzione del gestore eventi con la variabile nell'ambito, anziché impostare un attributo di dati sull'elemento. Questo non ti impedisce di accedere agli attributi degli elementi se lo desideri, ma non è il modo idiomatico di accedere a una variabile in React.
tytk,

8
<div className='btn' onClick={(e) =>
     console.log(e.currentTarget.attributes['tag'].value)}
     tag='bold'>
    <i className='fa fa-bold' />
</div>

quindi e.currentTarget.attributes['tag'].valuefunziona per me


5

Puoi accedere agli attributi dei dati in questo modo

event.target.dataset.tag

4

Questa singola riga di codice ha risolto il problema per me:

event.currentTarget.getAttribute('data-tag')

3

Non conosco React, ma nel caso generale puoi passare attributi personalizzati come questo:

1) definire all'interno di un tag html un nuovo attributo con prefisso dati

data-mydatafield = "asdasdasdaad"

2) ottenere da JavaScript con

e.target.attributes.getNamedItem("data-mydatafield").value 

Il mio continua a dire null
Si8,

3

Se qualcuno sta cercando di utilizzare event.target in React e trova un valore nullo, è perché un SyntheticEvent ha sostituito event.target. SyntheticEvent ora contiene 'currentTarget', come in event.currentTarget.getAttribute ('data-username').

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

Sembra che React lo faccia in modo che funzioni su più browser. È possibile accedere alle vecchie proprietà tramite un attributo nativeEvent.


3

Prova invece di assegnare le proprietà dom (che è lento) passa semplicemente il tuo valore come parametro per la funzione che crea effettivamente il gestore:

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

sembra un grande commento! come posso vedere che è molto più lento assegnare le proprietà del dom
Ido Bleicher il

2

Puoi semplicemente usare l' oggetto event.target.dataset . Questo ti darà l'oggetto con tutti gli attributi di dati.


0

In React non hai bisogno dei dati html, usa una funzione restituisce un'altra funzione; in questo modo è molto semplice inviare parametri personalizzati e puoi accedere ai dati personalizzati e all'evento.

render: function() {
...
<a style={showStyle} onClick={this.removeTag(i)}></a>
...
removeTag: (i) => (event) => {
    this.setState({inputVal: i}); 
},
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.