Como acessar atributos personalizados do objeto de evento no React?

214

O React é capaz de renderizar atributos personalizados, conforme descrito em http://facebook.github.io/react/docs/jsx-gotchas.html :

Se você quiser usar um atributo customizado, prefixe-o com data-.

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

E isso é uma ótima notícia, exceto que não consigo encontrar uma maneira de acessá-lo a partir do objeto de evento, por exemplo:

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

O elemento e a data-propriedade são renderizados em html fine. Propriedades padrão como stylepodem ser acessadas como event.target.styleperfeitas. Em vez de event.targeteu tentei:

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

nada disso funcionou.

andriy_sof
fonte
1
Pode ser que um comentário ajude alguém, descobri que o React 16.7 não é renderizado novamente e atualize os atributos html personalizados do componente se você os tiver alterado apenas em uma loja (fe redux) e vinculado ao componente. Isso significa que o componente possui fe aria-modal=true, você envia as alterações (para false) para o armazenamento de atributos de ária / dados , mas nada mais é alterado (como o conteúdo, classe ou variáveis ​​do componente), pois o ReactJs não atualiza ária / dados atraem nesses componentes. Eu estive brincando o dia inteiro para perceber isso.
AlexNikonov 13/02/19

Respostas:

171

Para ajudá-lo a obter o resultado desejado de uma maneira talvez diferente da solicitada:

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

Observe o bind() . Como tudo isso é javascript, você pode fazer coisas úteis assim. Não precisamos mais anexar dados aos nós do DOM para controlá-los.

Na IMO, isso é muito mais limpo do que depender de eventos DOM.

Atualização de abril de 2017: Hoje em dia eu escreveria em onClick={() => this.removeTag(i)}vez de.bind

Jared Forsyth
fonte
17
mas você não recebe mais o objeto de evento.
Chovy
9
@chovy Corrija-me se estiver errado, mas nem todas as funções javascript são inerentemente variadas? Não testei isso, mas suponho que o "objeto de evento" ainda está sendo passado. É apenas NÃO no mesmo índice de parâmetro que era anteriormente. A ligação da maneira descrita acima é como unshifta matriz de argumentos da função . Se o "objeto de evento" estivesse no índice 0, agora estaria no índice 1.
Ryder Brooks
8
@chovy Você pode, se precisar. Apenas façaremoveTag: function(i, evt) {
Jared Forsyth
8
É mais limpo, mas todos esses vínculos têm um impacto no desempenho se você estiver realizando muitos deles.
El Yobo 26/02
296

event.targetfornece o nó DOM nativo, você precisa usar as APIs DOM regulares para acessar atributos. Aqui estão os documentos sobre como fazer isso: Usando atributos de dados .

Você pode fazer um event.target.dataset.tagou event.target.getAttribute('data-tag'); qualquer um funciona.

Sophie Alpert
fonte
24
reagir 0.13.3, o IE10 event.target.dataseté indefinido, mas event.target.getAttribute('data-tag')funciona. os outros navegadores estão bem. Obrigado
Andrey Borisko
Há algo de errado com essa abordagem? Por exemplo, dependendo de qual botão o usuário aperta, quero passar uma string para uma função. Eu esperava evitar fazer três funções no meu componente para cada caso.
22816 Michael J. Calkins
4
Essa resposta é melhor que a aceita em termos de desempenho. Fazer dessa maneira significa que não criamos uma nova função em cada renderização. Não apenas pula a criação de uma nova função a cada renderização, mas como a referência da função será a mesma sempre, componentes puros (ou memorizados) não a verão como uma função diferente. Portanto, ele não renderiza desnecessariamente o componente inteiro toda vez. Mesmo uma implementação personalizada de shouldComponentUpdateteria o mesmo problema, a menos que você apenas ignorasse completamente a função prop.
Michael Yaworski 31/05/19
Funciona perfeitamente bem
Ogbonna Vitalis
1
Eu uso texto datilografado. No meu caso, eu tive que usarevent.currentTarget.getAttibute('data-tag')
karianpour
50

Aqui está a melhor maneira que encontrei:

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

Esses atributos são armazenados em um "NamedNodeMap", que você pode acessar facilmente com o método getNamedItem.

roctimo
fonte
4
Você provavelmente deseja adicionar a .valuepara obter o valor real
Wikunia 29/09/16
Eu editei a resposta para adicionar o .valueno final como @Wikunia sugeriu
fguillen
25

Ou você pode usar um fechamento:

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
fonte
3
Obrigado, Tudor. Tentei sua solução e funciona mesmo sem ligação. Usei-o para alternar estilos no e.target.
21714 Andriy_sof 10:14
como você sabe que uma função interna conterá os argumentos do 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
fonte
1
adicione alguma descrição ao seu código para fazer com que outros entendam o código
Aniruddha Das
8

A partir do React v16.1.1 (2017), aqui está a solução oficial: https://reactjs.org/docs/handling-events.html#passing-arguments-to-event-handlers

TLDR: OP deve fazer:

render: function() {
...
<a style={showStyle} onClick={(e) => this.removeTag(i, e)}></a>
...
removeTag: function(i, event) {
    this.setState({inputVal: i}); 
}
tytk
fonte
1
De onde vem o 'i'?
Freshchris 28/02/19
2
ié o atributo personalizado que o OP queria passar de alguma forma. É alguma variável que está no escopo quando o aelemento é definido.
tytk
Não é isso que o OP quer. Eles desejam acessar um valor de atributo no elemento (a) com o manipulador onClick.
Design by Adrian
1
Meu argumento foi que a solução oficial é definir a função de manipulador de eventos com a variável no escopo, em vez de definir um atributo de dados no elemento. Isso não impede o acesso a atributos de elementos, se você realmente deseja, mas essa não é a maneira idiomática de acessar uma variável no React.
tytk 22/06/19
8
<div className='btn' onClick={(e) =>
     console.log(e.currentTarget.attributes['tag'].value)}
     tag='bold'>
    <i className='fa fa-bold' />
</div>

então e.currentTarget.attributes['tag'].valuefunciona para mim

Manindra Gautam
fonte
5

Você pode acessar atributos de dados algo como isto

event.target.dataset.tag
Rameez Iqbal
fonte
4

Esta única linha de código resolveu o problema para mim:

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

Eu não sei sobre o React, mas no caso geral, você pode transmitir atributos personalizados como este:

1) defina dentro de uma tag html um novo atributo com prefixo de dados

data-mydatafield = "asdasdasdaad"

2) obtenha do javascript com

e.target.attributes.getNamedItem("data-mydatafield").value 
jimver04
fonte
O meu continua dizendo null
Si8 06/07/19
3

Se alguém estiver tentando usar event.target no React e encontrar um valor nulo, é porque um SyntheticEvent substituiu o event.target. O SyntheticEvent agora contém 'currentTarget', como em event.currentTarget.getAttribute ('data-username').

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

Parece que o React faz isso para que funcione em mais navegadores. Você pode acessar as propriedades antigas por meio de um atributo nativeEvent.

Eduardo
fonte
3

Tente, em vez de atribuir propriedades dom (que é lenta), apenas passe seu valor como um parâmetro para a função que realmente cria seu manipulador:

render: function() {
...
<a style={showStyle} onClick={this.removeTag(i)}></a>
...
removeTag = (customAttribute) => (event) => {
    this.setState({inputVal: customAttribute});
}
msangel
fonte
parece um ótimo comentário! Como posso ver que muito mais lento atribuindo propriedades dom
Ido Bleicher
2

Você pode simplesmente usar o objeto event.target.dataset . Isso fornecerá o objeto com todos os atributos de dados.

Vikash Kumar
fonte
0

No React, você não precisa dos dados html, use uma função return uma outra função; assim, é muito simples enviar parâmetros personalizados e você pode acessar os dados personalizados e o evento.

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