Как получить доступ к пользовательским атрибутам из объекта события в React?


214

React может отображать пользовательские атрибуты, как описано на http://facebook.github.io/react/docs/jsx-gotchas.html :

Если вы хотите использовать пользовательский атрибут, вы должны поставить перед ним префикс data-.

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

И это отличная новость, за исключением того, что я не могу найти способ получить к нему доступ из объекта события, например:

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

Элемент и data-свойство рендеринга в HTML хорошо. Стандартные свойства, такие как styleмогут быть доступны как event.target.styleхорошо. Вместо того, чтобы event.targetя попытался:

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

ничего из этого не сработало.


1
Может быть, один комментарий поможет кому-то, я обнаружил, что React 16.7 не рендерит и не обновляет настраиваемые html-атрибуты компонента, если вы изменили только их в хранилище (например, избыточный) и привязали к компоненту. Это означает, что у компонента есть fe aria-modal=true, вы помещаете изменения (в false) в хранилище атрибутов aria / data , но ничего больше не изменяется (например, содержимое компонента или класс или переменные в нем), так как в результате ReactJ не будет обновлять aria / атрибуты данных в этих компонентах. Я целый день возился с этим, чтобы понять это.
AlexNikonov

Ответы:


171

Чтобы помочь вам получить желаемый результат, возможно, не так, как вы просили:

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

Обратите внимание на bind() . Поскольку это все javascript, вы можете делать удобные вещи, как это. Нам больше не нужно прикреплять данные к узлам DOM, чтобы отслеживать их.

ИМО это намного чище, чем полагаться на события DOM.

Обновление апрель 2017: в эти дни я бы написал onClick={() => this.removeTag(i)}вместо.bind


17
но вы больше не получаете переданный объект события.
Чови

9
@chovy Пожалуйста, поправьте меня, если я ошибаюсь, но разве все функции javascript не являются вариативными? Я не проверял это, но я бы предположил, что «объект события» все еще передается. Это просто НЕ с тем же индексом параметров, который был ранее. Связывание способом, описанным выше, похоже unshiftна массив аргументов функции . Если бы «объект события» был в индексе, 0он теперь был бы в индексе 1.
Райдер Брукс

8
@chovy Вы можете, если вам это нужно. Просто сделайremoveTag: function(i, evt) {
Джаред Форсайт

8
Это чище, но все эти связки имеют удар по производительности, если вы делаете их много.
Эль Йобо


297

event.targetдает вам нативный DOM-узел, затем вам нужно использовать обычные DOM API для доступа к атрибутам. Вот документы о том, как это сделать: Использование атрибутов данных .

Вы можете сделать либо event.target.dataset.tagили event.target.getAttribute('data-tag'); либо один работает.


24
реагирует 0.13.3, IE10 event.target.datasetне определен, но event.target.getAttribute('data-tag')работает. другие браузеры в порядке. Спасибо
Андрей Бориско

Что-то не так с этим подходом? Например, в зависимости от того, какую кнопку нажимает пользователь, я хочу передать строку в функцию. Я надеялся избежать трех функций в моем компоненте для каждого случая.
Майкл Дж. Калкинс

4
Этот ответ лучше принятого с точки зрения производительности. Это означает, что мы не создаем новую функцию для каждого рендера. Он не только пропускает создание новой функции при каждом рендеринге, но так как ссылка на функцию будет одинаковой каждый раз, чистые (или запомненные) компоненты не увидят ее как другую функцию. Следовательно, он не будет излишне перерисовывать весь компонент каждый раз. Даже пользовательская реализация shouldComponentUpdateбудет иметь ту же проблему, если вы просто полностью игнорируете функцию prop.
Майкл Яворский

Прекрасно работает
Огбонна Виталис

1
Я использую машинопись. В моем случае я должен был использоватьevent.currentTarget.getAttibute('data-tag')
karianpour

50

Вот лучший способ, который я нашел:

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

Эти атрибуты хранятся в «NamedNodeMap», к которому вы можете легко получить доступ с помощью метода getNamedItem.


4
Вы, вероятно, хотите добавить, .valueчтобы получить реальное значение
Wikunia

Я отредактировал ответ, чтобы добавить его .valueв конце, как предложил
@Wikunia

25

Или вы можете использовать закрытие:

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
Спасибо, Тюдор. Опробовал ваше решение, и оно работает даже без привязки. Я использовал его для переключения стилей на e.target.
andriy_sof

Как вы знаете, внутренняя функция будет содержать аргументы события?
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
добавьте описание к своему коду, чтобы другие поняли его
Анируддха Дас

8

Начиная с React v16.1.1 (2017), вот официальное решение: https://reactjs.org/docs/handling-events.html#passing-arguments-to-event-handlers

TLDR: OP должен делать:

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

1
Откуда пришло «я»?
Freshchris

2
iэто пользовательский атрибут, который OP хотел передать каким-либо образом. Это некоторая переменная, которая находится в области видимости, когда aэлемент определен.
tytk

Это не то, что хочет ОП. Они хотят получить доступ к значению атрибута элемента (a) с помощью обработчика onClick.
Дизайн Адриана

1
Я хотел сказать, что официальное решение - определить функцию-обработчик событий с переменной в области видимости, а не устанавливать атрибут данных для элемента. Это не мешает вам обращаться к атрибутам элементов, если вы действительно этого хотите, но это не идиоматический способ доступа к переменной в 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'].valueу меня так работает




3

Я не знаю о React, но в общем случае вы можете передать пользовательские атрибуты, как это:

1) определить внутри html-тега новый атрибут с префиксом данных

data-mydatafield = "asdasdasdaad"

2) получить из JavaScript с

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

Мой продолжает говорить
ноль

3

Если кто-то пытается использовать event.target в React и находит нулевое значение, это происходит потому, что SyntheticEvent заменил event.target. SyntheticEvent теперь содержит «currentTarget», например, в event.currentTarget.getAttribute («data-username»).

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

Похоже, что React делает это так, чтобы он работал во многих браузерах. Вы можете получить доступ к старым свойствам через атрибут nativeEvent.


3

Попробуйте вместо присвоения свойств dom (что медленно) просто передайте свое значение в качестве параметра функции, которая фактически создает ваш обработчик:

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

выглядит как отличный комментарий! Как я могу видеть, что это гораздо медленнее, присваивая свойства
Идо Блейхер

2

Вы можете просто использовать объект event.target.dataset . Это даст вам объект со всеми атрибутами данных.


0

В React вам не нужны html-данные, используйте функцию, возвращающую другую функцию; как это очень просто отправить пользовательские параметры, и вы можете получить доступ к пользовательским данным и событию.

render: function() {
...
<a style={showStyle} onClick={this.removeTag(i)}></a>
...
removeTag: (i) => (event) => {
    this.setState({inputVal: i}); 
},
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.