DOM-атрибуты в React 16

8 Сентября, 2017. Dan Abramov(Дэн Абрамов)

В прошлом React игнорировал неизвестные DOM-атрибуты. Если бы вы написали JSX с атрибутом, который React не распознает, React бы просто пропустил его. Например, данный код:


Код
    
  // Ваш код:
  <div mycustomattribute="something" />
  

в React 15 стал бы в результате пустым div в DOM:


Код
    
  // результат в React 15:
  <div />
  

В React 16 мы вносим изменения. Теперь любые неизвестные атрибуты попадут в DOM:


Код
    
  // результат в React 16:
  <div mycustomattribute="something" />
  

React всегда предоставляет JavaScript-ориентированный API для DOM. Поскольку компоненты React часто принимают как пользовательские, так и связанные с DOM свойства, для React имеет смысл использовать верблюжью нотацию также как DOM API:


Код
    
  <div tabIndex="-1" />
  

Здесь ничего не изменилось. Однако способ, каким мы достигали этого в прошлом, заставлял нас хранить список всех допустимых атрибутов React DOM в бандле:


Код
    
  // ...
  summary: 'summary',
  tabIndex: 'tabindex'
  target: 'target',
  title: 'title',
  // ...
  

Это имело два недостатка:

  • Вы не могли передать пользовательский атрибут. А такая возможность полезна для предоставления нестандартных, специфических для браузера атрибутов, использования новых DOM API и интеграции с упрямыми сторонними библиотеками.
  • Список атрибутов продолжал расти с течением времени, но большинство канонических имен атрибутов React уже валидны в DOM. Удаление большей части списка помогло нам немного уменьшить размер бандла.

С новым подходом обе эти проблемы были решены. В React 16 вы можете передавать пользовательские атрибуты всем элементам HTML и SVG, а React не нужно включать весь список атрибутов в production версию.

Обратите внимание, что вы все равно должны использовать каноническое React именование для известных атрибутов:


Код
    
  // Можно
  <div tabIndex="-1" />
  


Код
    
  // Warning: Invalid DOM property `tabindex`. Did you mean `tabIndex`?
  <div tabIndex="-1" />
  

Другими словами, способ использования компонентов DOM в React не изменился, но теперь у вас есть новые возможности.

Нет. Мы не рекомендуем хранить данные в атрибутах DOM. Даже если вам нужно, data- атрибуты, вероятно, являются лучшим подходом, но в большинстве случаев данные должны храниться в состоянии React компонента или внешних хранилищах.

Однако новая возможность удобна, если вам нужно использовать нестандартный или новый атрибут DOM, или если вам нужно интегрироваться с сторонней библиотекой, которая полагается на такие атрибуты.

Как и раньше, React позволяет вам свободно передавать data- и aria- атрибуты:


Код
    
  <div data-foo="42" />
  <button aria-label="Close" onClick={onClose} />
  

Это поведение не изменилось.

Понятность очень важна, поэтому, несмотря на то, что React 16 передает любые атрибуты, он все еще проверяет, чтобы aria- свойства имели правильные имена в режиме разработки, как это делал React 15.

Мы включили предупреждение об неизвестных атрибутах, начиная с React 15.2.0, который вышел более года назад. Подавляющее большинство сторонних библиотек уже обновили свой код. Если ваше приложение на React 15.2.0 или выше не создает предупреждений, это изменение не требует модификаций в вашем коде.

Если вы по-прежнему где-то случайно передаете не-DOM атрибуты DOM-компонентам, в React 16 вы начнете видеть эти атрибуты в DOM, например:


Код
    
  <div myData='[Object object]' />
  

Это отчасти безопасно (браузер просто игнорирует такие атрибуты), но мы рекомендуем избавлять код от таких случаев. Одна потенциальная опасность заключается в том, что если вы передаете объект, который реализует собственный toString () или valueOf () метод – он выдаст исключение. Другая возможная проблема заключается в том, что теперь устаревшие атрибуты HTML, такие как align и valign, будут переданы в DOM. Раньше они удалялись, потому что React их не поддерживал.

Чтобы избежать этих проблем, мы рекомендуем исправить предупреждения, которые вы видите в React 15, перед обновлением до React 16.

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

Эти изменения влияют только на компоненты DOM, такие как <div>, а не на ваши собственные компоненты.

Ниже приведен их подробный список.

  • Неизвестные атрибуты со строками, цифрами и объектами:
    Код
        
      <div mycustomattribute="value" />
      <div mycustomattribute={42} />
      <div mycustomattribute={myObject} />
      

    React 15: Предупреждает и игнорирует их.
    React 16: Преобразует значения в строки и передает их.
    Примечание: атрибуты, начинающиеся с on, не передаются как исключение, поскольку это может стать потенциальной дырой в безопасности.

  • Известные атрибуты с отличным каноническим React именем:
    Код
        
      <div tabindex="-1" />
      <div class="hi" />
      

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

  • Небулевые атрибуты с булевыми значениями:
    Код
        
      <div className={false} />
      

    React 15: Преобразует булевы значения в строки и передает их.
    React 16: Предупреждает и игнорирует их.

  • Несобытийные атрибуты со значениями типа Function:
    Код
        
      <div className={function() {}} />
      

    React 15: Преобразует функции в строки и передает их.
    React 16: Предупреждает и игнорирует их.

  • Атрибуты со значениями типа Symbol:
    Код
        
      <div className={Symbol('foo')} />
      

    React 15: Ломается.
    React 16: Предупреждает и игнорирует их.

  • Атрибуты с значениями NaN:
    Код
        
      <div tabIndex={0 / 0} />
      

    React 15: Преобразует NaN в строке и передает ее.
    React 16: Преобразует NaN в строку и передает ее с предупреждением.

При тестировании этого релиза мы также создали автоматически генерируемую таблицу для всех известных атрибутов, чтобы отслеживать потенциальные регрессии.

Вы можете попробовать эти изменения на CodePen .

Он использует React 16 RC. Вы также можете помочь нам в тестировании используя RC в вашем проекте!

Большая работа была проделана Натаном Хунзакером, который был плодотворным внешним контрибьютором React.

Вы можете найти его работу над данной проблемой в нескольких PR в течение прошлого года: #6459, #7311, #10229, #10397, #10385 и #10470.

Значительные изменения в популярном проекте могут занять много времени и исследований. Натан продемонстрировал настойчивость и решимость добиться этих изменений, и мы очень благодарны ему за эти и другие усилия.

Мы также хотели бы поблагодарить Брэндона Дайла и Джейсона Куэнса за их неоценимую помощь в поддержке React в этом году.

Мы не изменяем работу пользовательских элементов в React 16, но существуют дискуссии об установке свойств вместо атрибутов, и мы можем пересмотреть это в React 17. Не стесняйтесь присоединиться, если вы хотите помочь!