¿Cómo acceder a los atributos personalizados desde el objeto de evento en React?

214

React puede representar atributos personalizados como se describe en http://facebook.github.io/react/docs/jsx-gotchas.html :

Si desea utilizar un atributo personalizado, debe anteponerlo con datos-.

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

Y esa es una gran noticia, excepto que no puedo encontrar una manera de acceder desde el objeto del evento, por ejemplo:

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

El elemento y la data-propiedad se procesan en html bien. styleSe puede acceder a las propiedades estándar como event.target.stylebien. En lugar de event.targetlo intenté:

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

ninguno de estos funcionó.

andriy_sof
fuente
1
Puede ser un comentario que ayude a alguien, descubrí que React 16.7 no se retracta y actualiza los atributos html personalizados del componente si solo los cambiaste en una tienda (fe redux) y lo vinculaste al componente. Esto significa que el componente tiene fe aria-modal=true, empuja los cambios (a falso) al almacén de atributos aria / datos , pero no se cambia nada más (como el contenido del componente o la clase o las variables allí) como resultado, ReactJs no actualizará aria / atributos de datos en esos componentes. He estado jugando todo el día para darme cuenta de eso.
AlexNikonov

Respuestas:

171

Para ayudarlo a obtener el resultado deseado tal vez de una manera diferente a la que solicitó:

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

Note el bind(). Debido a que todo esto es javascript, puede hacer cosas útiles como esa. Ya no necesitamos adjuntar datos a los nodos DOM para realizar un seguimiento de ellos.

En mi opinión, esto es mucho más limpio que confiar en eventos DOM.

Actualización de abril de 2017: en estos días escribiría en onClick={() => this.removeTag(i)}lugar de.bind

Jared Forsyth
fuente
17
pero ya no se pasa el objeto de evento.
chovy
99
@chovy Corríjame si me equivoco, pero ¿no son todas las funciones de JavaScript inherentemente variables? No he probado esto, pero supongo que el "objeto de evento" todavía se está pasando. Simplemente NO está en el mismo índice de parámetro que estaba anteriormente. La vinculación de la manera descrita anteriormente es como unshiftla matriz de argumentos de función . Si el "objeto de evento" estuviera en el índice 0, ahora estaría en el índice 1.
Ryder Brooks
8
@chovy Puedes si lo necesitas. Just doremoveTag: function(i, evt) {
Jared Forsyth
8
Es más limpio, pero todos esos enlaces tienen un éxito de rendimiento si estás haciendo muchos de ellos.
El Yobo
296

event.targetle proporciona el nodo DOM nativo, luego debe usar las API DOM regulares para acceder a los atributos. Aquí hay documentos sobre cómo hacerlo: Uso de atributos de datos .

Puedes hacer cualquiera event.target.dataset.tago event.target.getAttribute('data-tag'); Cualquiera de los dos funciona.

Sophie Alpert
fuente
24
reacciona 0.13.3, IE10 event.target.datasetno está definido pero event.target.getAttribute('data-tag')funciona. Los otros navegadores están bien. Gracias
Andrey Borisko
¿Hay algo malo con este enfoque? Por ejemplo, dependiendo de qué botón presione el usuario, quiero pasar una cadena a una función. Esperaba evitar hacer tres funciones en mi componente para cada caso.
Michael J. Calkins
44
Esta respuesta es mejor que la aceptada en términos de rendimiento. Hacerlo de esta manera significa que no creamos una nueva función en cada render. No solo omite la creación de una nueva función en cada renderizado, sino que dado que la referencia de la función será la misma cada vez, los componentes puros (o memorizados) no la verán como una función diferente. Por lo tanto, no volverá a representar innecesariamente todo el componente cada vez. Incluso una implementación personalizada de shouldComponentUpdatetendría el mismo problema a menos que ignorara por completo la función prop.
Michael Yaworski
Funciona perfectamente bien
Ogbonna Vitalis
1
Yo uso mecanografiado. En mi caso tuve que usarevent.currentTarget.getAttibute('data-tag')
karianpour
50

Aquí está la mejor manera que encontré:

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

Esos atributos se almacenan en un "NamedNodeMap", al que puede acceder fácilmente con el método getNamedItem.

roctimo
fuente
44
Probablemente desee agregar un .valuepara obtener el valor real
Wikunia
He editado la respuesta para agregarla .valueal final como sugirió
@Wikunia
25

O puede usar un cierre:

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
fuente
3
Gracias Tudor Intenté su solución y funciona incluso sin vinculación. Lo usé para alternar estilos en e.target.
andriy_sof
¿Cómo sabes que una función interna contendrá los argumentos del evento?
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
fuente
1
agregue alguna descripción a su código para que otros entiendan el código
Aniruddha Das
8

A partir de React v16.1.1 (2017), aquí está la solución oficial: https://reactjs.org/docs/handling-events.html#passing-arguments-to-event-handlers

TLDR: OP debe hacer:

render: function() {
...
<a style={showStyle} onClick={(e) => this.removeTag(i, e)}></a>
...
removeTag: function(i, event) {
    this.setState({inputVal: i}); 
}
tytk
fuente
1
¿De dónde viene la 'i'?
Freshchris
2
ies el atributo personalizado que OP quería pasar de alguna manera. Es una variable que está dentro del alcance cuando ase define el elemento.
tytk
Eso no es lo que OP quiere. Quieren acceder a un valor de atributo en el elemento (a) con el controlador onClick.
Diseño de Adrian
1
Mi punto fue que la solución oficial es definir la función de controlador de eventos con la variable en el alcance, en lugar de establecer un atributo de datos en el elemento. Esto no te impide acceder a los atributos de los elementos si realmente quieres, pero esa no es la forma idiomática de acceder a una variable en React.
tytk
8
<div className='btn' onClick={(e) =>
     console.log(e.currentTarget.attributes['tag'].value)}
     tag='bold'>
    <i className='fa fa-bold' />
</div>

entonces e.currentTarget.attributes['tag'].valuefunciona para mi

Manindra Gautam
fuente
5

Puede acceder a los atributos de datos de esta manera

event.target.dataset.tag
Rameez Iqbal
fuente
4

Esta única línea de código resolvió el problema para mí:

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

No sé sobre React, pero en el caso general puede pasar atributos personalizados como este:

1) definir dentro de una etiqueta html un nuevo atributo con prefijo de datos

data-mydatafield = "asdasdasdaad"

2) obtener de javascript con

e.target.attributes.getNamedItem("data-mydatafield").value 
jimver04
fuente
El mío sigue diciendo nulo
Si8
3

Si alguien está tratando de usar event.target en React y encuentra un valor nulo, es porque un SyntheticEvent ha reemplazado el event.target. SyntheticEvent ahora contiene 'currentTarget', como en event.currentTarget.getAttribute ('data-username').

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

Parece que React hace esto para que funcione en más navegadores. Puede acceder a las propiedades antiguas a través de un atributo nativeEvent.

Eduardo
fuente
3

Intente en lugar de asignar propiedades dom (que es lenta) simplemente pase su valor como un parámetro para funcionar que realmente cree su controlador:

render: function() {
...
<a style={showStyle} onClick={this.removeTag(i)}></a>
...
removeTag = (customAttribute) => (event) => {
    this.setState({inputVal: customAttribute});
}
msangel
fuente
parece un gran comentario! ¿Cómo puedo ver que es mucho más lento asignar propiedades dom?
Ido Bleicher
2

Simplemente puede usar el objeto event.target.dataset . Esto le dará el objeto con todos los atributos de datos.

Vikash Kumar
fuente
0

En React no necesita los datos html, use una función para devolver otra función; así es muy simple enviar parámetros personalizados y puedes acceder a los datos personalizados y al evento.

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