Jak uzyskać dostęp do niestandardowych atrybutów z obiektu zdarzenia w React?

214

React jest w stanie renderować niestandardowe atrybuty zgodnie z opisem na stronie http://facebook.github.io/react/docs/jsx-gotchas.html :

Jeśli chcesz użyć niestandardowego atrybutu, powinieneś go poprzedzić danymi.

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

I to jest dobra wiadomość, ale nie mogę znaleźć sposobu, aby uzyskać do niej dostęp z obiektu zdarzenia, np .:

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

Element i data-właściwość są renderowane w formacie HTML. styleDostęp do standardowych właściwości, takich jak, można uzyskać w event.target.styleporządku. Zamiast event.targetpróbowałem:

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

żaden z nich nie działał.

andriy_sof
źródło
1
Może być jeden komentarz, który może komuś pomóc, dowiedziałem się, że React 16.7 nie rerenderuje i aktualizuje niestandardowe atrybuty HTML komponentu, jeśli zmieniłeś tylko je w sklepie (np. Redux) i powiązałeś z komponentem. Oznacza to, że komponent ma fe aria-modal=true, przesuwasz zmiany (do wartości false) do magazynu atrybutów aria / data , ale nic innego się nie zmienia (takie jak zawartość komponentu lub klasa lub zmienne w nim zawarte), w wyniku czego ReactJs nie zaktualizuje aria / atrasy danych w tych komponentach. Przez cały dzień bawiłem się, żeby to zrozumieć.
AlexNikonov

Odpowiedzi:

171

Aby pomóc Ci uzyskać pożądany rezultat w inny sposób niż poprosiłeś:

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

Zwróć uwagę na bind(). Ponieważ to wszystko jest javascript, możesz robić takie przydatne rzeczy. Nie musimy już dołączać danych do węzłów DOM w celu ich śledzenia.

IMO jest to o wiele czystsze niż poleganie na zdarzeniach DOM.

Aktualizacja kwietnia 2017 r .: W dzisiejszych czasach pisałbym onClick={() => this.removeTag(i)}zamiast.bind

Jared Forsyth
źródło
17
ale nie otrzymujesz już obiektu zdarzenia.
chovy
9
@chovy Proszę mnie poprawić, jeśli się mylę, ale czy wszystkie funkcje javascript są z natury variadic? Nie testowałem tego, ale zakładam, że „obiekt zdarzenia” wciąż jest przekazywany. Po prostu NIE ma tego samego indeksu parametrów, jak poprzednio. Wiązanie w sposób opisany powyżej jest jak tablica argumentówunshift funkcji . Gdyby „obiekt zdarzenia” był w indeksie , teraz byłby w indeksie . 01
Ryder Brooks,
8
@chovy Możesz, jeśli potrzebujesz. Po prostu zróbremoveTag: function(i, evt) {
Jared Forsyth,
8
Jest czystszy, ale wszystkie wiązania mają hit wydajności, jeśli robisz dużo z nich.
El Yobo
297

event.targetdaje natywny węzeł DOM, a następnie musisz użyć zwykłych interfejsów API DOM, aby uzyskać dostęp do atrybutów. Oto dokumenty, jak to zrobić: Korzystanie z atrybutów danych .

Można wykonać jedną event.target.dataset.taglub event.target.getAttribute('data-tag'); jedno z nich działa.

Sophie Alpert
źródło
24
zareaguj 0.13.3, IE10 event.target.datasetjest niezdefiniowany, ale event.target.getAttribute('data-tag')działa. inne przeglądarki są w porządku. Dzięki
Andrey Borisko,
Czy jest coś nie tak z tym podejściem? Na przykład w zależności od tego, który przycisk naciska użytkownik, chcę przekazać ciąg do funkcji. Miałem nadzieję uniknąć trzech funkcji w moim komponencie dla każdego przypadku.
Michael J. Calkins,
4
Ta odpowiedź jest lepsza od przyjętej pod względem wydajności. Wykonanie tego w ten sposób oznacza, że nie tworzymy nowej funkcji na każdym renderowaniu. Nie tylko pomija tworzenie nowej funkcji przy każdym renderowaniu, ale ponieważ odwołanie do funkcji będzie za każdym razem takie samo, komponenty czyste (lub zapamiętywane) nie będą postrzegały jej jako innej funkcji. Dlatego nie będzie niepotrzebnie ponownie renderować całego komponentu za każdym razem. Nawet niestandardowa implementacja shouldComponentUpdatemiałaby ten sam problem, chyba że całkowicie zignorowałeś prop funkcji.
Michał Yaworski
Działa idealnie dobrze
Ogbonna Vitalis
1
Używam maszynopisu. W moim przypadku musiałem użyćevent.currentTarget.getAttibute('data-tag')
karianpour
50

Oto najlepszy sposób, jaki znalazłem:

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

Te atrybuty są przechowywane w „NamedNodeMap”, do którego można łatwo uzyskać dostęp za pomocą metody getNamedItem.

roctimo
źródło
4
Prawdopodobnie chcesz dodać a, .valueaby uzyskać rzeczywistą wartość
Wikunia,
Zredagowałem odpowiedź, aby dodać .valuena końcu, jak sugeruje
@Wikunia
25

Lub możesz użyć zamknięcia:

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
źródło
3
Dzięki, Tudor. Wypróbowałem swoje rozwiązanie i działa nawet bez wiązania. Użyłem go do przełączania stylów w e.target.
andriy_sof
skąd wiesz, że funkcja wewnętrzna będzie zawierać argumenty zdarzenia?
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
źródło
1
dodaj opis do kodu, aby inni mogli go zrozumieć
Aniruddha Das
8

Począwszy od wersji 16.1.1 React (2017), oto oficjalne rozwiązanie: https://reactjs.org/docs/handling-events.html#passing-arguments-to-event-handlers

TLDR: OP powinien wykonać:

render: function() {
...
<a style={showStyle} onClick={(e) => this.removeTag(i, e)}></a>
...
removeTag: function(i, event) {
    this.setState({inputVal: i}); 
}
tytk
źródło
1
Skąd pochodzi „i”?
Freshchris
2
ijest niestandardowym atrybutem, który OP chciał jakoś przekazać. Jest to jakaś zmienna, która wchodzi w zakres, gdy aelement jest zdefiniowany.
tytk
Nie tego chce OP. Chcą uzyskać dostęp do wartości atrybutu elementu (a) za pomocą procedury obsługi onClick.
Projekt Adrian
1
Chodziło mi o to, że oficjalnym rozwiązaniem jest zdefiniowanie funkcji obsługi zdarzeń ze zmienną o zasięgu, zamiast ustawiania atrybutu danych dla elementu. To nie powstrzymuje cię przed dostępem do atrybutów elementów, jeśli naprawdę tego chcesz, ale to nie jest idiomatyczny sposób dostępu do zmiennej w React.
tytk
8
<div className='btn' onClick={(e) =>
     console.log(e.currentTarget.attributes['tag'].value)}
     tag='bold'>
    <i className='fa fa-bold' />
</div>

tak e.currentTarget.attributes['tag'].valuedziała dla mnie

Manindra Gautam
źródło
5

Możesz uzyskać dostęp do atrybutów danych czegoś takiego

event.target.dataset.tag
Rameez Iqbal
źródło
4

Ten pojedynczy wiersz kodu rozwiązał dla mnie problem:

event.currentTarget.getAttribute('data-tag')
Emeka Augustine
źródło
3

Nie wiem o React, ale w ogólnym przypadku możesz przekazać niestandardowe atrybuty:

1) Zdefiniuj w tagu HTML nowy atrybut z prefiksem danych

data-mydatafield = "asdasdasdaad"

2) pobierz z javascript za pomocą

e.target.attributes.getNamedItem("data-mydatafield").value 
jimver04
źródło
Moje powtarzają: null
Si8
3

Jeśli ktoś próbuje użyć event.target w React i znajduje wartość pustą, to dlatego, że SyntheticEvent zastąpił event.target. SyntheticEvent przechowuje teraz „currentTarget”, na przykład w event.currentTarget.getAttribute („data-username”).

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

Wygląda na to, że React robi to, dzięki czemu działa w wielu przeglądarkach. Możesz uzyskać dostęp do starych właściwości za pomocą atrybutu nativeEvent.

Eduardo
źródło
3

Spróbuj zamiast przypisywać właściwości dom (co jest wolne), po prostu przekaż swoją wartość jako parametr do funkcji, która faktycznie tworzy program obsługi:

render: function() {
...
<a style={showStyle} onClick={this.removeTag(i)}></a>
...
removeTag = (customAttribute) => (event) => {
    this.setState({inputVal: customAttribute});
}
msangel
źródło
wygląda na świetny komentarz! jak mogę zobaczyć, że znacznie wolniej przypisuje się właściwości domu
Ido Bleicher
2

Możesz po prostu użyć obiektu event.target.dataset . To da ci obiekt ze wszystkimi atrybutami danych.

Vikash Kumar
źródło
0

W React nie potrzebujesz danych HTML, użyj funkcji zwróć inną funkcję; w ten sposób wysyłanie niestandardowych parametrów jest bardzo proste i można uzyskać dostęp do niestandardowych danych i zdarzenia.

render: function() {
...
<a style={showStyle} onClick={this.removeTag(i)}></a>
...
removeTag: (i) => (event) => {
    this.setState({inputVal: i}); 
},
Miguel Savignano
źródło