React: RFC: план для атрибутов / свойств настраиваемых элементов в React 18

Созданный на 24 окт. 2017  ·  129Комментарии  ·  Источник: facebook/react

Это предназначено для адреса # 7249. В документе описаны плюсы и минусы различных подходов, которые React может использовать для обработки атрибутов и свойств пользовательских элементов.

TOC / Резюме

  • Фон
  • Предложения

    • Вариант 1. Установить только свойства

    • Плюсы



      • Легко понять / реализовать


      • Избегает конфликта с будущими глобальными атрибутами


      • Использует преимущества настраиваемого элемента «апгрейд»


      • Пользовательские элементы обрабатываются как любой другой компонент React



    • Минусы



      • Возможно критическое изменение


      • Требуется ссылка для установки атрибута


      • Непонятно, как будет работать рендеринг на стороне сервера



    • Вариант 2: Свойства - при наличии

    • Плюсы



      • Неразрывное изменение



    • Минусы



      • Разработчикам необходимо понимать эвристику


      • Возврат к атрибутам может конфликтовать с будущими глобальными переменными



    • Вариант 3: отличать свойства с помощью сигилы

    • Плюсы



      • Неразрывное изменение, на которое разработчики могут согласиться


      • Подобно тому, как другие библиотеки обрабатывают атрибуты / свойства


      • Система явная



    • Минусы



      • Это новый синтаксис


      • Непонятно, как будет работать рендеринг на стороне сервера



    • Вариант 4. Добавьте объект атрибутов

    • Плюсы



      • Система явная


      • Расширение синтаксиса также может решить проблемы с обработкой событий.



    • Минусы



      • Это новый синтаксис


      • Это может быть переломное изменение


      • Это может быть более крупное изменение, чем любое из предыдущих предложений.



    • Вариант 5. API для использования пользовательских элементов

    • Плюсы



      • Система явная


      • Неразрывное изменение


      • Идиоматический реагировать



    • Минусы



      • Для сложного компонента может потребоваться много работы


      • Может увеличиваться размер связки


      • Конфигурация должна идти в ногу с компонентом



Фон

Когда React пытается передать данные пользовательскому элементу, он всегда делает это с использованием атрибутов HTML.

<x-foo bar={baz}> // same as setAttribute('bar', baz)

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

<x-foo bar="[object Object]">

Чтобы решить эту проблему, используйте ref чтобы вручную установить свойство.

<x-foo ref={el => el.bar = baz}>

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

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

Предложения

Вариант 1. Установить только свойства

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

Пример:

<x-foo bar={baz}>

Выше код приведет к React установки .bar свойство x-foo элемент , равный значению baz .

Для имен свойств camelCased React может использовать тот же стиль, что и сегодня, для таких свойств, как tabIndex .

<x-foo squidInk={pasta}> // sets .squidInk = pasta

Плюсы

Легко понять / реализовать

Эта модель проста, ясна и согласуется с «JavaScript-ориентированным API для DOM» React.

Любой элемент, созданный с помощью таких библиотек, как Polymer или Skate, автоматически создает свойства для поддержки своих открытых атрибутов. Все эти элементы должны «просто работать» с описанным выше подходом. Разработчикам, создающим ванильные компоненты вручную, рекомендуется подкреплять атрибуты свойствами, поскольку они отражают современные (то есть не такие странные, как <input> ) элементы HTML5 ( <video> , <audio> и т. Д.) были реализованы.

Избегает конфликта с будущими глобальными атрибутами

Когда React устанавливает атрибут в настраиваемый элемент, всегда есть риск, что будущая версия HTML будет поставлять атрибут с таким же названием и что-то сломает. Эта проблема обсуждалась с авторами спецификации, но четкого решения проблемы нет. Полное исключение атрибутов (кроме случаев, когда разработчик явно устанавливает атрибут с помощью ref ) может обойти эту проблему до тех пор, пока браузеры не предложат лучшее решение.

Использует преимущества настраиваемого элемента «апгрейд»

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

Пользовательские элементы обрабатываются как любой другой компонент React

Когда компоненты React передают данные друг другу, они уже используют свойства. Это просто заставит настраиваемые элементы вести себя одинаково.

Минусы

Возможно критическое изменение

Если разработчик вручную создавал ванильные пользовательские элементы, у которых есть только API атрибутов, им нужно будет обновить свой код, иначе их приложение сломается. Исправление заключалось бы в использовании ref для установки атрибута (объяснено ниже).

Требуется ссылка для установки атрибута

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

<custom-element ref={el => el.setAttribute('my-attr', val)} />

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

Непонятно, как будет работать рендеринг на стороне сервера

Неясно, как эта модель будет отображаться на пользовательские элементы рендеринга на стороне сервера. React может предположить, что свойства сопоставлены с одноименными атрибутами и попытаться установить их на сервере, но это далеко не пуленепробиваемое и, возможно, потребует эвристики для таких вещей, как свойства camelCased -> атрибуты в тире.

Вариант 2: Свойства - при наличии

Во время выполнения React может попытаться определить, присутствует ли свойство в настраиваемом элементе. Если свойство присутствует, React будет использовать его, в противном случае он вернется к установке атрибута. Это модель, которую Preact использует для работы с настраиваемыми элементами.

Реализация псевдокода:

if (propName in element) {
  element[propName] = value;
} else {
  element.setAttribute(propName.toLowerCase(), value);
}

Возможные шаги:

  • Если у элемента есть определенное свойство, React будет использовать его.

  • Если у элемента есть неопределенное свойство, и React пытается передать ему примитивные данные (строка / число / логическое значение), он будет использовать атрибут.

    • Альтернатива: предупреждать и не устанавливать.
  • Если элемент имеет неопределенное свойство, и React пытается передать ему объект / массив, он установит его как свойство. Это потому, что some-attr = "[object Object]" бесполезен.

    • Альтернатива: предупредить и не устанавливать.
  • Если элемент отображается на сервере, и React пытается передать ему строку / число / логическое значение, он будет использовать атрибут.

  • Если элемент отображается на сервере, и React пытается передать ему объект / массив, он ничего не сделает.

Плюсы

Неразрывное изменение

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

Минусы

Разработчикам необходимо понимать эвристику

Разработчики могут быть сбиты с толку, когда React устанавливает атрибут вместо свойства в зависимости от того, как они выбрали загрузку своего элемента.

Возврат к атрибутам может конфликтовать с будущими глобальными переменными

Себастьян выразил обеспокоенность тем, что использование in для проверки наличия свойства в настраиваемом элементе может случайно обнаружить свойство в суперклассе (HTMLElement).

Существуют также другие потенциальные конфликты с глобальными атрибутами, которые обсуждались ранее в этом документе.

Вариант 3: отличать свойства с помощью сигилы

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

Пример проблеска:

<custom-img @src="corgi.jpg" @hiResSrc="[email protected]" width="100%">

В приведенном выше примере символ @ указывает, что src и hiResSrc должны передавать данные в настраиваемый элемент с использованием свойств, а width следует сериализовать в строку атрибутов.

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

h / t к @developit из Preact за предложение такого подхода :)

Плюсы

Неразрывное изменение, на которое разработчики могут согласиться

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

Подобно тому, как другие библиотеки обрабатывают атрибуты / свойства

Подобно Glimmer, и Angular, и Vue используют модификаторы, чтобы различать атрибуты и свойства.

Пример Vue:

<!-- Vue will serialize `foo` to an attribute string, and set `squid` using a JavaScript property -->
<custom-element :foo="bar” :squid.prop=”ink”>

Угловой пример:

<!-- Angular will serialize `foo` to an attribute string, and set `squid` using a JavaScript property -->
<custom-element [attr.foo]="bar” [squid]=”ink”>

Система явная

Разработчики могут точно сказать React, что они хотят, вместо того, чтобы полагаться на эвристику, такую ​​как подход « свойства, если они доступны» .

Минусы

Это новый синтаксис

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

Непонятно, как будет работать рендеринг на стороне сервера

Следует ли переключить сигилу на использование атрибута с таким же названием?

Вариант 4. Добавьте объект атрибутов

React может добавить дополнительный синтаксис, который позволяет авторам явно передавать данные в виде атрибутов. Если разработчики не используют этот объект атрибутов, их данные будут передаваться с использованием свойств JavaScript.

Пример:

const bar = 'baz';
const hello = 'World';
const width = '100%';
const ReactElement = <Test
  foo={bar} // uses JavaScript property
  attrs={{ hello, width }} // serialized to attributes
/>;

Эта идея была первоначально предложена @treshugart , автором Skate.js, и реализована в библиотеке val .

Плюсы

Система явная

Разработчики могут точно сказать React, что они хотят, вместо того, чтобы полагаться на эвристику, такую ​​как подход « свойства, если они доступны» .

Расширение синтаксиса также может решить проблемы с обработкой событий.

Примечание: это выходит за рамки этого документа, но, возможно, стоит упомянуть :)

Проблема № 7901 требует, чтобы React обошел свою систему синтетических событий при добавлении декларативных обработчиков событий к настраиваемым элементам. Поскольку имена событий настраиваемых элементов представляют собой произвольные строки, это означает, что они могут быть написаны с заглавной буквы любым способом. Чтобы обойти систему синтетических событий сегодня, также потребуется придумать эвристику для сопоставления имен событий из JSX в addEventListener .

// should this listen for: 'foobar', 'FooBar', or 'fooBar'?
onFooBar={handleFooBar}

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

const bar = 'baz';
const hello = 'World';
const SquidChanged = e => console.log('yo');
const ReactElement = <Test
  foo={bar}
  attrs={{ hello }}
  events={{ SquidChanged}} // addEventListener('SquidChanged', …)
/>;

В этой модели имя переменной используется как имя события. Никакой эвристики не требуется.

Минусы

Это новый синтаксис

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

Это может быть переломное изменение

Если какие-либо компоненты уже полагаются на свойства с именами attrs или events , это может их сломать.

Это может быть более крупное изменение, чем любое из предыдущих предложений.

Для React 17 может быть проще внести инкрементное изменение (например, одно из предыдущих предложений) и позиционировать это предложение как что-то, что нужно принять во внимание для более позднего, более крупного рефакторинга.

Вариант 5. API для использования пользовательских элементов

Это предложение было предложено @sophiebits и @gaearon из команды React.

React может создать новый API для использования настраиваемых элементов, который сопоставляет поведение элемента с объектом конфигурации.

Пример псевдокода:

const XFoo = ReactDOM.createCustomElementType({
  element: ‘x-foo’,
  ‘my-attr’: // something that tells React what to do with it
  someRichDataProp: // something that tells React what to do with it
});

Приведенный выше код возвращает прокси-компонент XFoo который знает, как передавать данные в настраиваемый элемент в зависимости от предоставленной вами конфигурации. Вы могли бы использовать этот прокси-компонент в своем приложении вместо прямого использования настраиваемого элемента.

Пример использования:

<XFoo someRichDataProp={...} />

Плюсы

Система явная

Разработчики могут указать React именно то поведение, которое они хотят.

Неразрывное изменение

Разработчики могут отказаться от использования объекта или продолжить использование текущей системы.

Идиоматический реагировать

Это изменение не требует нового синтаксиса JSX и больше похоже на другие API в React. Например, PropTypes (даже если он перемещается в отдельный пакет) имеет в чем-то похожий подход.

Минусы

Для сложного компонента может потребоваться много работы

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

Может увеличиваться размер связки

В связи с вышеизложенным, каждый класс настраиваемых элементов теперь несет стоимость своего определения + размер его объекта конфигурации.

Примечание: я не уверен на 100%, правда ли это.

Конфигурация должна идти в ногу с компонентом

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

Копия @sebmarkbage @gaearon @developit @treshugart @justinfagnani

DOM Discussion

Самый полезный комментарий

Привет, ребята, пока мы ждем, я создал прокладку для упаковки вашего веб-компонента в React https://www.npmjs.com/package/reactify-wc

import React from "react";
import reactifyWc from "reactify-wc";

// Import your web component. This one defines a tag called 'vaadin-button'
import "@vaadin/vaadin-button";

const onClick = () => console.log('hello world');

const VaadinButton = reactifyWc("vaadin-button");

export const MyReactComponent = () => (
  <>
    <h1>Hello world</h1>
    <VaadinButton onClick={onClick}>
      Click me!
    </VaadinButton>
  </>
)

Надеюсь, это окажется полезным

(Это мой первый набег на OSS и один из первых открытых исходников чего-то вне моего офиса. Конструктивная критика более чем приветствуется 😄)

Все 129 Комментарий

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

Вариант 3 является обратно совместимым, декларативным и явным. Нет необходимости поддерживать эвристику отката, и другие библиотеки уже предоставляют аналогичные сигилы / модификаторы.

Приносим извинения за долгое чтение, но я хотел убедиться, что тщательно изучаю каждый вариант. Я не хочу слишком сильно искажать свое мнение, но если бы у меня была возможность выбирать, я бы выбрал вариант 3.
Вариант 3 является обратно совместимым, декларативным и явным. Нет необходимости поддерживать эвристику отката, и другие библиотеки уже предоставляют аналогичные сигилы / модификаторы.

Я между вариантом 2 и вариантом 3, я думаю, что React очень хорошо справлялся с поведением и изменениями API в прошлом. Введение предупреждений и ссылок на документы может помочь разработчикам понять, что происходит внутри.

Вариант 3 выглядит привлекательно из-за его декларативного характера, при чтении кода JSX новые разработчики сразу узнают, что React будет делать при рендеринге элемента.

Комментарии к варианту 2

Разработчики могут быть сбиты с толку, когда React устанавливает атрибут вместо свойства в зависимости от того, как они выбрали загрузку своего элемента.

Должны ли потребители настраиваемого элемента понимать это различие? Или это важно только для автора настраиваемого элемента? Похоже, что автору элемента нужно будет обрабатывать атрибуты для всего, что используется в HTML (поскольку это единственный способ передачи данных при использовании HTML) и свойств, если они хотят поддерживать сложные значения или свойство, получаемое / устанавливаемое из DOM. Возможно даже, что автор может изначально реализовать что-то как атрибут, а затем добавить свойство с тем же именем для поддержки более гибких типов данных и по-прежнему поддерживать свойство со значением, хранящимся в атрибутах.

Конфликты именования с будущими атрибутами и свойствами HTMLElement кажутся слабым местом в стандартах веб-компонентов в целом, поскольку это может привести к ошибкам независимо от подхода к привязке.

Если элемент имеет неопределенное свойство, и React пытается передать ему объект / массив, он установит его как свойство. Это потому, что some-attr = "[object Object]" бесполезен.

Кажется запутанным связывать по-разному в зависимости от значения. Если автор элемента не указал средство получения / установки свойства для обработки значения, тогда установка свойства приведет к тому, что элемент будет вести себя так, как если бы значение никогда не указывалось, что может быть труднее отлаживать.

Комментарии к варианту 3

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

Должны ли потребители настраиваемого элемента понимать это различие? Или это важно только для автора настраиваемого элемента?

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

Конфликты именования с будущими атрибутами и свойствами HTMLElement кажутся слабым местом в стандартах веб-компонентов в целом, поскольку это может привести к ошибкам независимо от подхода к привязке.

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

Я должен добавить, что для свойств это неплохо, потому что свойство, определяемое элементом, затеняет будущее свойство, добавленное в HTMLElement. Поэтому, если вы передавали данные в настраиваемый элемент как свойство js, он продолжал бы работать. Основная проблема, похоже, связана с атрибутами, поскольку они глобальны.

Кажется запутанным связывать по-разному в зависимости от значения. Если автор элемента не указал средство получения / установки свойства для обработки значения, тогда установка свойства приведет к тому, что элемент будет вести себя так, как если бы значение никогда не указывалось, что может быть труднее отлаживать.

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

Верно, что если автор не определяет геттер / сеттер для значения, это не будет очень полезно. Но также бесполезно иметь my-attr=[object Object] . И поскольку вы не знаете, действительно ли свойство не определено или их определение просто загружается лениво, кажется, что безопаснее всего установить свойство.

Другой потенциальный недостаток варианта 3 заключается в том, что он требует, чтобы потребитель настраиваемого элемента знал, реализовал ли элемент что-либо как свойство или как атрибут.

Я думаю, что вы, по сути, сегодня в той же лодке, потому что нет ничего, что заставляло бы автора настраиваемого элемента определять атрибут вместо свойства. Таким образом, у меня может быть элемент с API только для свойств, который не будет получать никаких данных из текущей системы React, и мне нужно знать, как использовать ref для непосредственной установки свойств js.

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

[редактировать]

Как вы заявили в своем предыдущем пункте:

Похоже, что автору элемента нужно будет обрабатывать атрибуты для всего, что используется в HTML (поскольку это единственный способ передачи данных при использовании HTML) и свойств, если они хотят поддерживать сложные значения или свойство, получаемое / устанавливаемое из DOM.

Поскольку вы никогда не знаете, как пользователь попытается передать данные вашему элементу, вам все равно потребуется соответствие атрибут-свойство. Я полагаю, если бы вариант 3 был поставлен, большинство людей просто связывало бы все с помощью символа @ потому что это было бы проще всего. Вот как я сегодня работаю с пользовательскими элементами во Vue, поскольку они предоставляют модификатор .prop .

он требует, чтобы потребитель настраиваемого элемента знал, реализовал ли элемент что-то как свойство или как атрибут

React не должен беспокоиться об этом, как сказал Роб, на мой взгляд, это ответственность автора настраиваемого элемента информировать пользователя о том, как этот элемент работает.

И это действительно то, как нам нужно сделать это сегодня, например, подумайте об элементе <video> , допустим, вам нужно отключить его или изменить текущее время внутри компонента.

muted работает как логический атрибут

render() {
  return (
    <div className="video--wrapper">
      <video muted={ this.state.muted } />
    </div>
  );
}

На текущий момент вам нужно создать ref указывающий на элемент видео, и изменить свойство.

render() {
  return (
    <div className="video--wrapper">
      <video ref={ el => this.video = el } muted={ this.state.muted } />
    </div>
  );
}

Затем создайте обработчик событий, метод экземпляра и вручную установите свойство для элемента DOM.

onCurrenTimeChange(e) {
  this.video.currentTime = e.value;
}

Если вы думаете об этом, это как бы нарушает декларативную модель, которую React сам навязывает своим API и абстрактным слоем JSX, поскольку currentTime явно является состоянием в компоненте оболочки, с привязкой свойств нам все равно понадобится обработчик событий, но Модель абстракции JSX была бы более декларативной, и ссылки для этого не понадобились бы:

render() {
  return (
    <div className="video--wrapper">
      <video muted={ this.state.muted } @currentTime={ this.state.currentTime } />
    </div>
  );
}

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

@cjorasch мои два цента :)

Если бы мы проектировали это с нуля, без необходимости учитывать обратную совместимость, я думаю, что вариант 1 был бы наиболее идиоматическим для React «JavaScript-ориентированный API для DOM» .

Что касается рендеринга на стороне сервера, можно ли решить эту проблему, предоставив API для кода приложения, чтобы сообщить React о том, как сопоставить свойства настраиваемого элемента с атрибутами? Похоже на карты, которые React уже поддерживает для определенных платформой атрибутов? Этот API нужно будет вызывать только один раз для каждого имени настраиваемого элемента (не для каждого его экземпляра) и только для свойств, которые не следуют прямому соответствию 1: 1 со своим атрибутом, что, будем надеяться, должно быть относительно редко.

Если мы обеспокоены тем, что это слишком серьезное изменение, то я думаю, что вариант 3 также довольно привлекателен. Если сигил обозначает свойство, я бы предложил ".", Поскольку это уже средство доступа к свойствам в JavaScript. Однако я считаю, что неудачно заставлять каждый экземпляр того, где пользовательский элемент используется в приложении, знать, когда использовать атрибут, а когда использовать свойство. Что я предпочитаю в варианте 1, так это то, что даже если требуется свойство для сопоставления атрибутов, этот код сопоставления может быть изолирован от всех видов использования JSX.

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

Может я не понимаю процесс обновления. Элементы обычно имеют свойства, определенные как геттеры / сеттеры в прототипе класса. Проверка propName in element вернет истину из-за существования геттера / сеттера, даже если значение свойства все еще не определено. Во время обновления устанавливаются ли значения свойств для некоторого временного экземпляра, а затем копируются в фактический экземпляр после завершения ленивой загрузки?

Обновление - это процесс, при котором настраиваемый элемент получает свой класс. До этого он не был экземпляром этого класса, поэтому методы получения и установки свойств недоступны.

@jeremenichelli

отключено работает как логический атрибут

только что проверен, и у него также есть соответствующее свойство, хотя оно, похоже, не задокументировано в MDN: P

На текущий момент вам нужно создать ссылку, указывающую на элемент видео, и изменить свойство.

Да, иногда вы встретите API-интерфейсы только для свойств в современных HTML-элементах. currentTime обновляется с высокой частотой, поэтому не имеет смысла отражать его в атрибуте HTML.

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

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

@robdodson yeap, я тоже знал о свойстве приглушенного звука 😄 Я просто использовал эти два, чтобы доказать, что уже _in the wild_ нет универсального правила, как вы упомянули.

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

При написании последнего фрагмента кода мне понравилась привязка свойств 💟

@effulgentsia

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

Я думаю, что это уже происходит сегодня. Поскольку основные библиотеки настраиваемых элементов (полимеры, коньки, возможно, другие?) Автоматически создают поддерживающие свойства для всех открытых атрибутов, разработчики могли просто использовать сигил для каждого свойства настраиваемого элемента. Вероятно, им в редких случаях потребуется переключиться на использование атрибута.

@cjorasch

RE: обновление. Как упоминалось в @effulgentsia , можно иметь настраиваемый элемент на странице, но загрузить его определение позже. <x-foo> изначально будет экземпляром HTMLElement и когда я загружу его определение позже, он "обновится" и станет экземпляром класса XFoo . На этом этапе выполняются все его обратные вызовы жизненного цикла. Мы используем эту технику в проекте Polymer Starter Kit. Примерно так:

<app-router>
  <my-view1></my-view1>
  <my-view2></my-view2>
</app-router>

В приведенном выше примере мы не будем загружать определение для my-view2 пока маршрутизатор не изменится на него.

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

разработчики могут просто использовать сигил для каждого свойства в настраиваемом элементе

Если бы разработчики начали это делать, то как это будет отличать использование свойства, потому что вы «можете» от использования свойства, потому что вы «должны»? И разве это не дифференциация, необходимая для рендеринга на стороне сервера?

Если бы разработчики начали это делать, то как это будет отличать использование свойства, потому что вы «можете» от использования свойства, потому что вы «должны»?

Извините, возможно я неправильно сформулировал это. Я имел в виду, что разработчики, скорее всего, будут использовать сигилу, потому что она даст наиболее последовательный результат. Вы можете использовать его для передачи примитивных данных или богатых данных, таких как объекты и массивы, и он всегда будет работать. Я думаю, что работа со свойствами во время выполнения обычно предпочтительнее работы с атрибутами, поскольку атрибуты, как правило, используются больше для начальной конфигурации.

И разве это не дифференциация, необходимая для рендеринга на стороне сервера?

Может случиться так, что на сервере сигил вернется к установке атрибута.

Может случиться так, что на сервере сигил вернется к установке атрибута.

Я не думаю, что это сработает, если причина для сигилы в том, что это свойство, которое не существует как атрибут, например currentTime видео.

дифференцировать использование свойства, потому что вы «можете» от использования свойства, потому что вы «должны»

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

Что касается рендеринга на стороне сервера, можно ли решить эту проблему, предоставив API для кода приложения, чтобы сообщить React о том, как сопоставить свойства настраиваемого элемента с атрибутами?

Чтобы быть более конкретным, я предлагаю что-то вроде этого:

ReactDOM.defineCustomElementProp(elementName, propName, domPropertyName, htmlAttributeName, attributeSerializer)

Примеры:

// 'muted' can be set as either a property or an attribute.
ReactDOM.defineCustomElementProp('x-foo', 'muted', 'muted', 'muted')

// 'currentTime' can only be set as a property.
ReactDOM.defineCustomElementProp('x-foo', 'currentTime', 'currentTime', null)

// 'my-attribute' can only be set as an attribute.
ReactDOM.defineCustomElementProp('x-foo', 'my-attribute', null, 'my-attribute')

// 'richData' can be set as either a property or an attribute.
// When setting as an attribute, set it as a JSON string rather than "[object Object]".
ReactDOM.defineCustomElementProp('x-foo', 'richData', 'richData', 'richdata', JSON.stringify)

Для чего-то, что может быть только свойством (где htmlAttributeName имеет значение null), SSR пропустит рендеринг и затем обработает его на клиенте.

Для чего-то, что может быть только атрибутом (где domPropertyName имеет значение null), React вызовет setAttribute() как в настоящее время в v16.

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

Когда React встречает опору, для которой не было вызвано defineCustomElementProp() и которая не определена спецификацией HTML как глобальное свойство или атрибут, тогда React может реализовать некоторую логику по умолчанию. Например, возможно:

  • В версии 17 сохраните BC с v16 и установите как атрибут.
  • В версии 18 предположите, что это может быть любой из них, и следуйте наиболее оптимальной стратегии для этого.

Но в любом случае, сохраняя этот отдельный API, объекты JSX и props сохраняются в чистоте и в одном пространстве имен, как и для компонентов React и нестандартных HTML-элементов.

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

Эти вызовы ReactDOM.defineCustomElementProp() могут быть предоставлены в файле JS, поддерживаемом автором настраиваемого элемента (в том же репозитории, где поддерживается / распространяется настраиваемый элемент). Это не потребуется для настраиваемых элементов со строгим соответствием свойства / атрибута 1: 1, что в соответствии с инструкцией Background этой проблемы в любом случае является рекомендацией и случаем большинства. Таким образом, только авторы настраиваемых элементов, не соблюдающие эту рекомендацию, должны будут предоставить файл интеграции React. Если автор не предоставляет его (например, потому что автор настраиваемого элемента не заботится о React), то сообщество людей, использующих этот настраиваемый элемент в приложениях React, может самостоятельно организовать центральный репозиторий для размещения этого файла интеграции.

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

Я бы предпочел вариант 3, но это огромное изменение ... А как насчет обратного? Атрибуты имеют префикс, а не реквизит?

Сигилы в React, я не знаю, как я к этому отношусь. Спецификацию JSX следует рассматривать как универсальную, не слишком зависящую от специфики браузера, особенно от отклонений из-за обратной совместимости. obj[prop] = value и obj.setAttributes(props, value) ведут себя по-разному, это прискорбно, но, глядя на api браузеров в целом, не удивительно. @ : [] приведет к утечке деталей реализации и противоречит подходу, ориентированному на javascript. Поэтому, если у нас нет спецификации, которая делает следующее, я думаю, что это плохая идея: const data = <strong i="8">@myFunction</strong> // -> "[object Object]"

Если мне придется полагаться на веб-компонент, я был бы рад, если бы семантика была скрыта от React и JSX, а также чтобы они не вносили критических изменений. Из всех вариантов мне кажется выгодным оставить ref => ... на месте. ref специально разработан для доступа к объекту. И, по крайней мере, разработчик точно знает, что происходит, нет утечки сигил или новых атрибутов, которые могли бы сломать существующие проекты.

@LeeCheneler

Я бы предпочел вариант 3, но это огромное изменение ... А как насчет обратного? Атрибуты имеют префикс, а не реквизит?

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

@drcmda

ни новых атрибутов, которые могли бы сломать существующие проекты.

Вы можете пояснить, что вы имели в виду?

К вашему сведению, для всех, кто следит за обсуждением, я обновил RFC пятым вариантом, предложенным членами команды React.

@robdodson

Я имел в виду это:

Вариант 4. Добавьте объект атрибутов
Минусы
Это может быть переломное изменение

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

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

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

import XButton from './XButton';

и это создается

export default ReactDOM.createCustomElementType(...)

Это позволяет им заменять компонент React настраиваемым компонентом, который использует (или даже не использует) настраиваемые элементы в любой момент времени.

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

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

Я думаю, что следующим шагом здесь было бы написать подробное предложение о том, как должна выглядеть конфигурация, чтобы удовлетворить все распространенные варианты использования. Он должен быть достаточно убедительным для пользователей Custom element + React, поскольку, если он не отвечает на распространенные варианты использования (например, обработка событий), мы окажемся в подвешенном состоянии, где функция не дает достаточных преимуществ, чтобы компенсировать многословие. .

Основываясь на моем предыдущем комментарии , как насчет:

const XFoo = ReactDOM.createCustomElementType('x-foo', {
  propName1: {
    propertyName: string | null,
    attributeName: string | null,
    attributeSerializer: function | null,
    eventName: string | null,
  }
  propName2: {
  }
  ...
});

Тогда логика для каждой опоры React в экземпляре XFoo будет следующей:

  1. Если eventName для этой опоры не является нулевым, зарегистрируйте его как обработчик событий, который вызывает значение опоры (предполагается, что это функция).
  2. В противном случае, если рендеринг на стороне клиента и propertyName не равно null, установите для свойства element значение prop.
  3. В противном случае, если attributeName не равно нулю, установите для атрибута элемента строковое значение свойства. Если attributeSerializer не равно нулю, используйте его для строкового преобразования значения prop. В противном случае просто сделайте '' + propValue .

Элемент ввода бумаги Polymer имеет 37 свойств, поэтому он будет производить очень большую конфигурацию.

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

  • если значение является функцией:
eventName: the prop name,
  • еще:
propertyName: the prop name,
attributeName: camelCaseToDashCase(the prop name),

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

<XFoo prop1={propValue1} prop2={propValue2} events={event1: functionFoo, event2: functionBar}>
</XFoo>

@gaearon @effulgentsia что вы думаете о сочетании варианта 1 и варианта 5?

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

Вариант 5 предназначен для людей, которые хотят использовать что-то вроде бумажного ввода во всем своем приложении и действительно хотели бы предоставить весь его API всем членам своей команды.

Для SSR варианта 1 эвристика всегда может использовать атрибут при рендеринге на сервере. Свойство camelCase преобразуется в атрибут тире. Кажется, это довольно распространенный шаблон для библиотек веб-компонентов.

Мне очень нравится идея комбинации option1 + option5. Это означает, что для большинства пользовательских элементов:

<x-foo prop1={propValue1}>

будет работать так, как ожидалось: prop1 установлен как свойство на стороне клиента и как атрибут (в виде тире) на стороне сервера.

И люди могли переключиться на вариант 5 для всего, что им не подходит.

Это было бы серьезным изменением с точки зрения того, как работает React 16. Для всех, кто сталкивается с этой поломкой (например, они использовали настраиваемый элемент с атрибутами, не подкрепленными свойствами), они могут переключиться на вариант 5, но это все равно перерыв. Я оставляю это на усмотрение команды React, чтобы решить, приемлемо ли это.

Ах, вот что я получаю за то, что быстро прочитал это в поезде @robdodson 🤦‍♂️ ... Не очень-то фанат варианта 3 Я прочитал это как все, что касается реквизита с префиксом, отсюда и мои колебания.

Вариант 5 кажется разумным и простым.

Мне нравится, куда движется @effulgentsia . Есть ли причина, по которой этого не могло быть:

const XFoo = ReactDOM.createCustomElementType('x-foo', {
  propName1: T.Attribute,
  propName2: T.Event,
  propName3: T.Prop
})

Или ценно поддержка нескольких типов на одной опоре?

Я бы не решился с этим потоком, хотя

если значение является функцией:
eventName: имя опоры,
еще:
propertyName: имя свойства,
attributeName: camelCaseToDashCase (имя свойства),

Я не думаю, что я бы хотел, чтобы функция по умолчанию использовалась для события и назначала как propertyName, так и attributeName разумным? Когда вы хотите, чтобы обе поддерживались, чтобы имитировать вопрос выше? 🙂

@LeeCheneler :

Цитата из плюсов Варианта 1 обзора проблемы:

Любой элемент, созданный с помощью таких библиотек, как Polymer или Skate, автоматически создает свойства для поддержки своих открытых атрибутов. Все эти элементы должны «просто работать» с описанным выше подходом. Разработчикам, вручную создающим ванильные компоненты, рекомендуется подкреплять атрибуты свойствами, так как это отражает современные (т.е. не чудаки, такие как <input> ) элементы HTML5 ( <video> , <audio> и т. Д.) были реализованы.

Вот почему назначение как propertyName, так и attributeName является разумным: потому что оно отражает то, что на самом деле имеет место для элементов, которые соответствуют передовой практике. И благодаря тому, что React знает об этом, он позволяет React решать, что использовать в зависимости от ситуации: например, использовать свойства для рендеринга на стороне клиента и атрибуты для рендеринга на стороне сервера. Для настраиваемых элементов, которые не соответствуют передовой практике и имеют некоторые атрибуты без соответствующих свойств и / или некоторые свойства без соответствующих атрибутов, React должен знать об этом, чтобы свойства без атрибутов не отображались во время SSR и свойства. -less-атрибуты могут быть установлены с помощью setAttribute () во время рендеринга на стороне клиента.

С вашим предложением это потенциально может быть сделано с помощью флагов объединения битов, таких как:

propName1: T.Property | T.Attribute,

Однако это не дает возможности выразить, что имя атрибута отличается от имени свойства (например, camelCase на dash-case). Также он не предоставит способ выразить, как сериализовать расширенный объект в атрибут во время SSR (текущее поведение «[object Object]» бесполезно).

Я не думаю, что я бы хотел, чтобы функция по умолчанию использовала событие

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

Вот мысль о менее подробной версии моего предыдущего предложения :

const XFoo = ReactDOM.createCustomElementType('x-foo', {
  UNREFLECTED_ATTRIBUTES: [
    'my-attr-1',
    'my-attr-2',
  ],
  UNREFLECTED_PROPERTIES: [
    'myProp1',
    'myProp2',
  ],
  REFLECTED_PROPERTIES: {
    // This is default casing conversion, so could be omitted.
    someVeryLongName1: 'some-very-long-name-1',

    // In case anyone is still using all lowercase without dashes.
    someVeryLongName2: 'someverylongname2',

    // When needing to define a function for serializing a property to an attribute.
    someRichData: ['some-rich-data', JSON.stringify],
  },
});

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

Имеет смысл @effulgentsia 👍

Мне нравится ваш второй пример, но разве он не открыт для комбинаторного взрыва, если будет добавлено больше типов, например, события + все, что может иметь смысл?

- UNREFLECTED_ATTRIBUTES
- UNREFLECTED_PROPERTIES
- UNREFLECTED_EVENTS
- REFLECTED_PROPERTIES_ATTRIBUTES
- REFLECTED_PROPERTIES_EVENTS
- REFLECTED_ATTRIBUTES_EVENTS
- REFLECTED_PROPERTIES_ATTRIBUTES_EVENTS
...

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

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

Хотя я являюсь автором реализации варианта 4, мне всегда приходилось отделять атрибуты и события от свойств. В идеале я бы предпочел вариант 1. Практически я бы предпочел вариант 2 с аварийным люком.

Вариант 1 идеален, но есть много типов атрибутов, которые не имеют соответствующих свойств (aria / data), поэтому для них потребуется дополнительная эвристика, и если есть какие-либо крайние случаи, когда элементы могут иметь атрибут, который должен иметь свойство, но не реализовывать его по какой-либо причине. Я считаю, что этот вариант следует тщательно рассмотреть, но он может быть жизнеспособным в долгосрочной перспективе.

Вариант 2 предпочтительнее, потому что это безотказное изменение. Он будет работать во всех ситуациях, когда определение настраиваемого элемента регистрируется до создания экземпляра (или загружается до установки свойств). Предшествующим уровнем техники для этой опции является Preact (cc @developit), и до сих пор она работала хорошо. Пройдя по этому пути, мы получим достаточно надежную, безотказную реализацию, которая была подтверждена успешным вариантом React и работает в большинстве ситуаций. Во всяком случае, это дает React краткосрочное решение, в то время как лучшие решения оцениваются в долгосрочной перспективе.

Для ситуации (ситуация с?) , Где она не работает - отложенные загрузки пользовательских определений элементов и любым другим , которые мы еще не рассматривал - аварийный люк , как то , что сделал Инкрементальный DOM , может быть реализована. Это похоже на то, что предлагает @effulgentsia , но лучше масштабируется до x количества настраиваемых элементов. Если потребители хотят делать это для отдельных элементов, они все равно могут, потому что это всего лишь функция. Это позволяет React высказать свое мнение, избежать выхода и удовлетворить все сценарии использования, переложив ответственность за все крайние случаи на потребителя. Это также то, что я ранее обсуждал с @developit по поводу реализации в Preact. Согласование между Preact / React здесь было бы большой победой.

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

Эти вызовы ReactDOM.defineCustomElementProp() могут быть предоставлены в файле JS, поддерживаемом автором настраиваемого элемента.

Это свяжет реализацию настраиваемого элемента с реализацией конкретной библиотеки (в данном случае React). На мой взгляд, это слишком большая нагрузка для авторов нестандартных элементов. Более того, для авторов, не использующих React, уговоры дать определение приводит к политическим дискуссиям, которые никому не нужны.

Определение вызова такого API пользователем пользовательского элемента только с теми свойствами / атрибутами, которые пользователь фактически использует, - это меньше кода для поддержки и более выразительное.

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

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

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

В принципе: если люди могут не думать о конфигурации свойств каждый раз, когда они используют компонент, я бы предпочел такой подход. Вот почему я предложил вариант 5. Я считаю, что он более эргономичен, чем 3 и 4, но при этом одинаково гибок.

Варианты 1 и 2 не очень хорошо работают с серверным рендерингом (генерация HTML), а вариант 2 также создает опасность обновления для авторов веб-компонентов, где теперь добавление свойства с тем же именем, что и существующий атрибут, является критическим изменением. Если мы решим, что SSR бесполезен, тогда вариант 1 будет довольно привлекательным с точки зрения React. Я не знаю, будет ли он достаточно всеобъемлющим на практике - все ли авторы компонентов раскрывают через свойства?

@treshugart, не

Извините, @sophiebits только что увидел ваш ответ. Я хотел бы ответить на несколько пунктов, прочитав его еще несколько раз, но хотел бы быстро ответить на этот:

Я не знаю, будет ли он достаточно всеобъемлющим на практике - все ли авторы компонентов раскрывают через свойства?

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

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

Как бы то ни было, их ничто не заставляет использовать атрибуты. Определение настраиваемого элемента - это просто класс, поэтому разработчик может делать все, что захочет. Но на практике большинство людей предпочитают использовать такие абстракции, как Polymer или Skate, для создания своих компонентов, поэтому они получают API свойств бесплатно.

Возможно, тогда наилучшим подходом будет создание свойств всегда на стороне клиента, а затем поддержка карты конфигурации в стиле Варианта 5 с примитивными именами свойств для имен атрибутов для людей, которые хотят поддерживать SSR в своих приложениях.

@sophiebits : Я думаю, что это отличная идея, за исключением того, что это

<x-foo long-name={val} />

Но как насчет правила «делать свойства», если в имени свойства нет тире, и «делать атрибуты», если оно есть?

@robdodson : longname атрибут с longName недвижимость? На самом деле это кажется гораздо более распространенным шаблоном со встроенными элементами HTML и глобальными атрибутами (например, contenteditable => contentEditable ), но мне неясно, достаточно ли это сейчас не рекомендуется. для настраиваемых атрибутов элементов благодаря Polymer и Skate. Если проблема все еще существует, то существующий JSX с:

<x-foo longname={val} />

потерпит неудачу как набор свойств, если свойство равно longName .

@effulgentsia Я могу говорить только от props API автоматически выполняет одностороннюю синхронизацию / десериализацию из атрибутов и извлекает имя атрибута, заключая имя свойства в тире (camelCase становится верблюжьим регистром и т. Д.). Это поведение в целом можно настроить, но мы рекомендуем использовать вышеупомянутые передовые методы.

Как утверждают многие, реквизит усложняет SSR, и это серьезная проблема. Поскольку кажется, что большинство предпочтет вариант 1, может быть, мы попробуем продвинуться вперед с предложением @sophiebits о настройке реквизитов на клиенте, предоставляя резервное копирование / отображение? Полагаю, это означает, что атрибуты будут установлены на сервере?

В качестве примера, вот как вы можете реализовать перенос состояния и свойств с сервера на клиент с помощью Skate (и любого настраиваемого элемента, реализующего renderedCallback() и props и / или state setters. Сделать это на уровне настраиваемого элемента тривиально. Если бы React пошел по пути установки атрибутов на сервере, регидратация была бы практически такой же. Авторам компонентов Skate на самом деле не пришлось бы ничего делать, как мы Я уже предоставил им логику десериализации.

@robdodson Я бы сделал то же, что делает инкрементальная DOM. Это выглядело бы примерно так:

const isBrowser = true; // this would actually do the detection
const oldAttributeHook = ReactDOM.setAttribute;

// This is much like the IDOM impl but with an arguably more clear name.
ReactDOM.setAttribute = (element, name, value) => {
  // This is essentially option 2, but with the added browser check
  // to keep attr sets on the server.
  if (isBrowser && name in element) {
    element[name] = value;
  } else {
    oldAttributeHook(element, name, value);
  }
};

@sophiebits

вариант 2 также создает опасность обновления для авторов веб-компонентов, где теперь добавление свойства с тем же именем, что и существующий атрибут, является критическим изменением.

Я думаю, что этого может быть неизбежно, учитывая то, как атрибуты работают на платформе. Если вы используете SSR для настраиваемого элемента и, следовательно, должны писать в атрибут, вы также рискуете, что платформа будет поставлять атрибут с аналогичным именем в будущем. Как упоминалось ранее в @treshugart , я не думаю, что React (или вообще любая библиотека) может решить эту проблему. Это то, что я хочу обсудить с авторами спецификаций веб-компонентов в TPAC, чтобы посмотреть, сможем ли мы исправить это в пространстве пользовательских элементов.

Я не уверен, изменит ли это ваше мнение о варианте 2 😁, но я хотел упомянуть об этом, поскольку вариант 2 имеет несколько приятных бонусов, и Preact, похоже, доказывает это на практике.

Возможно, тогда наилучшим подходом будет создание свойств всегда на стороне клиента, а затем поддержка карты конфигурации в стиле Варианта 5 с примитивными именами свойств для имен атрибутов для людей, которые хотят поддерживать SSR в своих приложениях.

+1, я поддерживаю продолжение движения в этом направлении.


@effulgentsia

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

Вариант 2 решит это :)
В противном случае, вероятно, потребовалась бы эвристика в сочетании с вариантом 1, которая сопоставляет атрибуты с тире на свойства с верблюжьим регистром.

Но как насчет правила «делать свойства», если в имени свойства нет тире, и «делать атрибуты», если оно есть?

Похоже, что Preact установит атрибут, если в имени есть тире. Я предполагаю, что это потому, что они используют вариант 2, а long-name не проходит проверку in поэтому возвращается к атрибуту ( источнику ).

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

Известно ли вам о каких-либо структурах или практиках настраиваемых элементов, где у людей будет другой регистр атрибутов от соответствующего свойства, без тире?

Не то, что я знаю из. Тире - это простой способ для библиотеки узнать, куда девать верблюжий футляр. Если вы вручную создавали ванильный веб-компонент, вы могли бы сделать longname/longName и только вариант 2 спасет вас, потому что он не найдет свойство longname , но вернется к ранее используемому Атрибут longname .

Что бы это ни стоило, похоже, что Preact в крайнем случае вызовет toLowerCase() для свойства, которое он не распознает, перед установкой атрибута. Так что, если бы вы использовали SSR <x-foo longName={bar}/> он также правильно вернулся бы к атрибуту longname="" .


@treshugart

Может быть, мы попробуем продвинуться вперед с предложением @sophiebits о настройке реквизитов на клиенте, обеспечивая резервное копирование / отображение? Полагаю, это означает, что атрибуты будут установлены на сервере?

да и да.

Я бы сделал то же самое, что и инкрементальная DOM.

Есть ли идея, что каждый элемент (или их базовый класс) должен смешивать это?

Кстати, спасибо всем за то, что продолжаете участвовать в обсуждении, я знаю, что оно затянулось ❤️

Не уверен, что я понимаю последний пример в https://github.com/facebook/react/issues/11347#issuecomment -339858314, но маловероятно, что мы предоставим такой глобальный переопределяемый хук.

@gaearon Я думаю, что Трей просто показал чистое изменение как обезьяний-патч, предположительно, он будет записан в саму реализацию ReactDOM.

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

  1. Для BC ничего не меняйте в том, как строчные пользовательские элементы работают в React. Другими словами, JSX, такой как <x-foo ... /> , продолжит работать в React 17 так же, как и в 16. Или, если для него требуются _ незначительные_ исправления ошибок, откройте отдельную проблему, чтобы обсудить их.

  2. Добавьте API без конфигурации, чтобы создать компонент React с улучшенной семантикой настраиваемых элементов. Например, const XFoo = ReactDOM.customElement('x-foo'); .

  3. Для созданного выше компонента используйте следующую семантику:

  4. Для любого свойства в XFoo, которое является зарезервированным именем свойства React ( children , ref , любые другие?), Примените к нему обычную семантику React (не устанавливайте его как атрибут или свойство. на узле DOM настраиваемого элемента).
  5. Для любого глобального атрибута или свойства HTMLElement, определенного спецификацией HTML (включая data-* и aria-* ), проделайте то же самое с этими реквизитами, как то, что React сделал бы с ними, если бы они были на div элемент. Другими словами, то, как React применяет реквизиты для <XFoo data-x={} className={} contentEditable={} /> к узлу DOM, должно быть идентично тому, как он это делает для <div data-x={} className={} contentEditable={} /> (как для клиентской стороны, так и для SSR).
  6. Для любой опоры на XFoo, которая содержит тире (кроме глобальных атрибутов, разрешенных выше), выдать предупреждение (чтобы сообщить разработчику, что XFoo ориентирован на свойства, а не на атрибуты API) и ничего не делать с ним (ни установить его как свойство или атрибут).
  7. Для любого свойства в XFoo, которое начинается с подчеркивания или верхней буквы ASCII, ничего с ним не делать (и, возможно, выдать предупреждение?). Также не рекомендуется использовать имена свойств для пользовательских элементов, поэтому зарезервируйте эти пространства имен для будущей семантики (например, см. №4 ниже).
  8. Для всех других свойств в XFoo при рендеринге на стороне клиента установите его на узле DOM как свойство. Для SSR, если значение является примитивным, визуализируйте его как атрибут; если не примитивный, пропустите рендеринг и установите его как свойство на стороне клиента во время гидратации. Для рендеринга SSR в качестве атрибута укажите имя camelCaseToDashCase.

  9. Для компонентов, созданных с помощью API в # 2 выше, зарезервируйте имя свойства, которое будет использоваться для прослушивателей событий. Например, 'events' или 'eventListeners' . Или, если вы не хотите конфликтовать с этими потенциальными именами свойств настраиваемых элементов, тогда '_eventListeners' или 'EventListeners' . Созданная ReactDom реализация XFoo автоматически регистрирует эти прослушиватели событий на узле DOM.

  10. В крайних случаях (например, при использовании настраиваемого элемента, для которого указанная выше реализация нежелательна или недостаточна) разработчик приложения может реализовать свой собственный компонент React, чтобы делать все, что им нужно. То есть им не нужно использовать ReactDOM.customElement() иначе они могли бы его расширить.

  11. Для людей, которым требуется все вышеперечисленное поведение, но они хотят, чтобы в их JSX использовались строчные имена пользовательских элементов ( <x-foo /> вместо <XFoo /> , по тем же причинам, по которым люди, знакомые с написанием HTML, предпочитают <div> более <Div> ), они могут исправить React.createElement (). Это будет довольно простой патч обезьяны: просто возьмите первый аргумент и, если он соответствует имени настраиваемого элемента, для которого вы хотите это (будь то конкретный список или любая строка со всеми строчными буквами и хотя бы одним тире), затем вызовите ReactDOM.customElement() на это имя и перенаправить результат и оставшиеся аргументы исходному React.createElement() .

@developit @gaearon тоже может быть. Если «картографирование» было необходимо, я думаю, что крючок более устойчив. Однако это также должно было показать чистое изменение, если оно будет реализовано в ядре ReactDOM, как указал Джейсон.

Для BC ничего не меняйте в том, как строчные пользовательские элементы работают в React. Другими словами, JSX как продолжит работать в React 17 так же, как и в 16. Или, если для него требуются незначительные исправления ошибок, откройте отдельный вопрос для их обсуждения.

Лично я бы предпочел иметь возможность использовать мой элемент <x-foo> как есть и легко передавать ему свойства без необходимости сначала оборачивать его.

Если возможно, я бы предпочел вариант 1 (свойства на стороне клиента) и 5 ​​(конфигурация для SSR), предложенный @sohpiebits . Я все еще надеюсь, что, возможно, люди пересмотрят вариант 2 (может быть, вариант 2 + 5?) Для бонуса обратной совместимости.

@gaearon изменилось ли ваше мнение о предложении Трея, если оно является частью ядра ReactDOM? Может быть, мы могли бы конкретизировать пример, если бы это помогло?

Моя основная проблема с Вариантом 5 - это создание большого количества шаблонов для обеспечения взаимодействия, нарушение DX, было бы позором для всей основной команды React и участников потратить много времени на изменения, которые не будут иметь желаемого эффекта.

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

Я думаю, что решение, которое удовлетворит всех нас, будет сочетанием некоторых из этих опций, таких как _steps_, добавление API, предупреждение и устаревание или изменение поведения.

Возможно варианты 5 с предупреждением, позже вариант 2 с отказом от необходимой оболочки.

Возможно варианты 5 с предупреждением, позже вариант 2 с отказом от необходимой оболочки.

На самом деле я думал, что лучше сделать обратное. Вариант 1 или 2, потому что это менее кардинальное изменение. И измерить, как это происходит и как начинает выглядеть история SSR для веб-компонентов. Затем следует вариант 5, потому что он добавляет новый API и понятие компонентов прокси / оболочки.

Основная проблема с вариантом 1 в том, что это довольно большой разрыв BC. Основная проблема с вариантом 2 заключается в том, что он имеет состояние гонки, зависящее от того, когда элемент завершил обновление. Я не уверен, что любой из них действительно приемлем для проекта, который так широко используется, как React.

Учитывая доступность варианта 5, мне интересно, можем ли мы вместо этого сделать гораздо более безопасные, но все же полезные улучшения для использования без варианта 5. Например, как насчет варианта, обратного варианту 4: просто введите реквизиты domProperties и eventListeners , чтобы вы могли делать такие вещи, как:

<x-foo 
  my-attr1={...} 
  domProperties={{myRichDataProperty: ...}} 
  eventListeners={{'a-custom-element-event':  e => console.log('yo')}} 
/>

Это полностью обратно совместимо, потому что domProperties и eventListeners из-за прописных букв не являются допустимыми именами атрибутов . За исключением того, что React 16 в настоящее время вызывает setAttribute () даже для имен свойств с верхними альфами, полагаясь на то, что браузеры внутренне будут использовать строчные буквы в имени; однако, может ли будущий второстепенный выпуск React 16 выдавать предупреждение при обнаружении свойств настраиваемых элементов, которые не являются допустимыми именами атрибутов, чтобы люди могли исправить свои ошибки корпуса до обновления до React 17?

В дополнение к сохранению BC, этот подход легко понять: он ориентирован на атрибуты (то есть реквизиты React обрабатываются как атрибуты элемента), что подходит, учитывая, что само имя элемента все в нижнем регистре и имеет тире и, следовательно, ориентировано на HTML. Однако domProperties предоставляется для относительно редких случаев, когда вам нужно передать свойства, например, передать расширенные данные.

Для людей, которые хотят изменить свою ментальную модель, чтобы она была ориентирована на свойства (как вариант 1), вот где может пригодиться API стиля варианта 5:

const XFoo = ReactDOM.customElement('x-foo');
<XFoo prop1={} prop2={} data-foo={} aria-label={} />

В этом синтаксисе каждая опора рассматривается как свойство (вариант 1). Что подходит, потому что элемент «name» (XFoo) также следует соглашению, основанному на JS. Я думаю, что мы по-прежнему хотели бы поддерживать как минимум data-* и aria-* реквизиты, рассматриваемые как атрибуты, которые мы могли бы ограничить только этими атрибутами или обобщить, рассматривая любую опору с тире как атрибут.

Между тем, для поддержки варианта 5 конфигурации SSR мы могли бы добавить конфигурационный API в ReactDOM.customElement , например:

const XFoo = ReactDOM.customElement('x-foo', ssrConfiguration);

Возможно, ssrConfiguration может быть функцией обратного вызова, аналогичной ReactDOM.setAttribute one в комментарии @treshugart ?

Что вы думаете?

@effulgentsia Мне нравится, куда идут твои мысли. Немного измените имена: domProps / domEvents . Это очень близко к варианту 4.

WRT SSR, я думаю, что SSR может обрабатываться самими настраиваемыми элементами, если React может учитывать атрибуты, которые компонент мутирует на себя, если он не отслеживает их. Я опубликовал суть ранее, но здесь она снова для удобства: https://gist.github.com/treshugart/6eff0da3c0bea886bb56589f743b78a6. По сути, компонент применяет атрибуты после рендеринга на сервере и повторно гидрирует их на клиенте. SSR для веб-компонентов возможен, но решения все еще обсуждаются на уровне стандартов, поэтому, возможно, лучше подождать с этой частью предложения.

@effulgentsia Мне также нравится, куда вы направляетесь. @sophiebits , @gaearon do
у вас есть мысли по этому поводу?

Во вторник, 31 октября 2017 г., 19:33 Trey Shugart [email protected] написал:

@effulgentsia https://github.com/effulgentsia Мне нравится, где ваш
мысли идут. Немного изменив названия, может быть полезно
выровняйте их имена: domProps / domEvents или что-то в этом роде.

Вариант 2 WRT, он, по крайней мере, обратно совместим и решает большинство вариантов использования,
но я подхожу к альтернативам.

Я думаю, что SSR может обрабатываться самими пользовательскими элементами, если
React может уважать атрибуты, которые компонент мутирует в себя, если он
не отслеживая их. Я опубликовал суть ранее, но вот она снова, для
удобство:
https://gist.github.com/treshugart/6eff0da3c0bea886bb56589f743b78a6.
По сути, компонент применяет атрибуты после рендеринга на сервере.
и восстанавливает их на клиенте. SSR для веб-компонентов возможен, но
решения все еще обсуждаются на уровне стандартов, так что это может быть
Лучше дождаться этой части предложения здесь.

-
Вы получаете это, потому что вас упомянули.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/facebook/react/issues/11347#issuecomment-340960798 ,
или отключить поток
https://github.com/notifications/unsubscribe-auth/ABBFDeiQhBWNGXNplbVV1zluYxT-ntFvks5sx9hngaJpZM4QD3Zn
.

Немного измените имена: domProps / domEvents.

Они мне нравятся. Я также занимаюсь мозговым штурмом, есть ли способ сделать их еще более идиоматичными для React, заменив концепцию «dom» концепцией «ref». Другими словами: refProps / refEvents , поскольку они предназначены для присоединения реквизитов и слушателей событий к «ref».

И тогда я подумал, что если вместо того, чтобы вводить новые специальные имена внутри this.props , мы просто перегрузим существующий атрибут ref JSX. В настоящее время «ref» - ​​это функция, которая вызывается, когда компонент React монтируется и размонтируется. Что, если бы мы позволили ему также быть объектом вот так:

<x-foo my-attr-1={}
  ref={{
    props: ...
    events: ...
    mounted: ...
    unmounted: ...
  }}
/>

Просто идея.

Мне такой подход очень нравится :)

Дружелюбный пинг по этому поводу. @gaearon @sophiebits есть ли у вас какие-нибудь мысли по поводу последнего предложения

Мы только что открыли RFC-процесс. Можем ли мы попросить кого-нибудь из вас представить его как RFC?
https://github.com/reactjs/rfcs

Я бы предпочел не добавлять domProperties и eventListeners "props" (или эквивалент в объекте ref = {{}}), потому что это делает использование пользовательских элементов очень неестественным и в отличие от всех других компонентов React. Если пользователю компонента необходимо четко понимать разницу между свойствами и атрибутами и т. Д., Я бы предпочел сделать это как решение в стиле ReactDOM.createCustomElementType. Затем, если вы используете компонент ровно один раз, это сопоставимый объем работы (указание конфигурации, а затем использование ее один раз), но если вы используете компонент много раз, вам не нужно каждый раз думать об объекте конфигурации. Требование указывать конфигурацию каждый раз, кажется, противоречит цели иметь чистую интеграцию настраиваемых элементов, если только я чего-то не упускаю.

@sophiebits Хорошо, я мог бы попытаться написать RFC для чего-то в этом роде. Что вы думаете об идее, о которой вы вернулись 26 октября, о том, чтобы сначала использовать свойства на стороне клиента, а также разрешить людям писать ReactDOM.createCustomElementType для SSR и / или если им нужен действительно точный контроль над тем, как клиент отображает атрибуты / свойства ?

По крайней мере, со стилем createCustomElementType библиотеки могут легко сопоставить с ним свои API. Т.е. наш skatejs / renderer-react мог легко взять props и настроить пользовательский элемент для React. Тем не менее, этот сорт оставляет ваниль высоко и сухо, не отвлекаясь и не выполняя небольшой работы. Мне нравится предложение Роба о безопасном значении по умолчанию, позволяющем при этом детальный контроль. Это то, что сработает?

@robdodson Думаю, я

Вариант 3 пока что является лучшим вариантом, и он может работать с SSR, я объясню, как это сделать.

Пока все варианты сами по себе, кроме 3-х,

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

Вот универсальные правила, с которыми мы все согласны:

  • установка атрибутов с помощью setAttribute - это самый стандартный способ во вселенной передачи данных элементам способом, который соответствует 1 к 1 с декларативными атрибутами HTML. Это должно работать 100% времени как закон Вселенной, поэтому это единственный 100% гарантированный способ передачи данных элементам.
  • некоторые люди недовольны тем, что он был разработан только для струнных.
  • Некоторые элементы (я повторяю, _ только некоторые элементы_ ) принимают значения через свойства объекта, которые сопоставляются с определенными атрибутами. Это _не_ то, на что можно положиться в 100% случаев.
  • некоторым людям нравятся свойства объекта, потому что они могут принимать не строки

Итак, как минимум, если React хочет работать на 100% с _ каждым отдельным настраиваемым элементом во вселенной и не быть обузой для людей_ , тогда:

  • React должен понимать, что это не Бог, есть много других библиотек, которые люди используют помимо React,
  • Поэтому Реагировать Шоудом _by default_ просто передать данные через setAttribute , потому что это% стандарт 100.
  • React должен принять тот факт, что авторы настраиваемых элементов могут расширять / переопределять методы setAttribute в своих определениях классов, заставляя setAttribute принимать вещи, отличные от строк. Ярким примером могут быть библиотеки, такие как A-frame.
  • React должен согласиться с тем, что если автор настраиваемого элемента хочет, чтобы настраиваемый элемент работал со всеми возможными библиотеками, _ не только с React_, тогда этот автор будет полагаться на setAttribute чтобы сделать его элемент по умолчанию совместимым со всем, и если по умолчанию все библиотеки полагаются на атрибуты, тогда вся вселенная будет работать друг с другом. _Нет никаких «если», «а» или «но» по этому поводу! _ (Если только w3c / whatwg не внесет больших изменений)

Оооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооо

Затем мы можем подумать о последствиях элементов, иногда имеющих API объект-свойство:

  • разработчики могут использовать setAttribute зная, что это будет работать постоянно.
  • разработчики иногда могут воспользоваться свойствами объекта.
  • разработчики всегда должны знать, существует ли интерфейс объект-свойство для любого данного элемента (настраиваемого или нет).
  • Интерфейсы объект-свойство - это альтернативный интерфейс, который не обязательно отображает 1-к-1 с атрибутами.

Итак, с этим знанием атрибутов и свойств, решение в React, которое _ желает расширить стандарты на 100% и уважать законы вселенной_, должно:

  1. разрешить атрибутам работать 100% времени по умолчанию. Это означает, что <x-foo blah="blah" /> должен _по умолчанию_ сопоставляться с setAttribute и передавать значение вместе _неизменено_ . Это неизменное изменение. Фактически, это исправляющее изменение, которое в противном случае привело бы к передаче бессмысленной строки "[object Object]" .
  2. Придумайте альтернативный способ разрешить пользователю React _ опционально_ использовать реквизиты, если пользователь осознает, какие интерфейсы объект-свойство существуют, и хочет явно использовать эти интерфейсы.

Похоже, что вариант 3 с использованием сигилы (честно говоря, нетрудно изучить дополнительный синтаксис) - это решение, которое ближе всего к идеалу. Основываясь на этом вопросе SO , тогда единственный доступный символ - = , хотя выбор чего-то вроде & (с экранируемой формой, например, \& ) более читабелен. Например, если мне нужна конкретная опора:

<x-foo &blah="blah" />

Большинство других символов, охватываемых спецификацией синтаксиса WHATWG HTML, должны работать, и я надеюсь, что они работают, но это уже другая тема.

Вариант 3 пока что лучший вариант.

Если гидратация не используется на клиенте и, следовательно, реквизиты не имеют смысла в SSR, тогда, да ладно. Раньше это никогда не работало, и теперь это не нужно. SSR в стиле PHP или Java отправляет статический HTML без гидратации и на 100% полагается на атрибуты. Говорят, что если мы используем React SSR, мы, вероятно, будем использовать гидратацию на стороне клиента, а если мы не хотим гидратации, тогда мы просто должны знать, что в этом случае мы не должны использовать реквизиты. _Это просто. Все, что нужно сделать, чтобы отреагировать, - это прояснить это предостережение в документации.

Но!!! Это не все! Мы по-прежнему можем включить функции Варианта 5, чтобы дать людям больше контроля. С помощью такого API, как вариант 5,

  • Некоторые люди могут настроить, как некоторые атрибуты могут отображаться на реквизиты
  • И как некоторые реквизиты могут быть сопоставлены с атрибутами. Это может помочь людям заставить SSR работать даже с негидратирующим типом SSR!
  • мы можем позволить людям определить, «если этот атрибут записан, фактически передать его в эту опору, но если это SSR, не передавайте ее в опору», или «передать эту опору в этот атрибут только во время SSR, в противном случае сделайте то, что Я указал с помощью символа "и т. Д.

В конце концов, кажется, что следующее решение будет работать:

  • Вариант 3 с setAttribute используемым по умолчанию за кулисами,
  • с исправлением для # 10070, чтобы React не мешал людям,
  • и API, как в варианте 5, для дальнейшей настройки для тех, кто действительно в нем нуждается, включая способы настройки SSR, клиента или того и другого.

С Новым Годом!

Я хочу ответить на некоторые из вышеперечисленных пунктов, но опасаюсь, что эта тема уже _ невероятно_ длинной. Итак, извините за удлинение: P

Вот универсальные правила, с которыми мы все согласны:

установка атрибутов с помощью setAttribute - это самый стандартный способ передачи данных элементам в юниверсе таким образом, чтобы они соответствовали 1 к 1 с декларативными атрибутами HTML. Это должно работать 100% времени как закон Вселенной, поэтому это единственный 100% гарантированный способ передачи данных элементам.

Это не совсем так. В платформе нет ничего, что могло бы заставить настраиваемый элемент предоставлять интерфейс атрибутов. Вы можете так же легко создать тот, который принимает только свойства JS. Так что это не «гарантированный способ передачи данных». Отсутствие механизмов принуждения означает, что вы не можете полагаться ни на один стиль (атрибуты HTML или свойства JS) со 100% уверенностью.

некоторые люди недовольны тем, что он был разработан только для струнных.
Некоторые элементы (я повторяю, только некоторые элементы) принимают значения через свойства объекта, которые сопоставляются с определенными атрибутами. Это не то, на что можно положиться в 100% случаев.

Мы призываем людей даже не беспокоиться о создании атрибутов для свойств, которые принимают расширенные данные, такие как объекты / массивы. Это связано с тем, что некоторые данные нельзя сериализовать обратно в строку атрибута. Например, если одно из свойств вашего объекта является ссылкой на узел DOM, его фактически нельзя преобразовать в строку. Кроме того, когда вы структурируете и повторно анализируете объект, он теряет свою идентичность. Это означает, что если в нем есть ссылка на другой POJO, вы не можете использовать эту ссылку, так как вы создали совершенно новый объект.

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

поэтому React shoud по умолчанию просто передает данные через setAttribute, потому что это 100% стандарт.

Свойства JavaScript такие же стандартные. Большинство элементов HTML предоставляют как атрибуты, так и соответствующий интерфейс свойств. Например, <img src=""> или HTMLImageElement.src .

React должен принять тот факт, что авторы настраиваемых элементов могут расширять / переопределять методы setAttribute в своих определениях классов, заставляя setAttribute принимать вещи, отличные от строк.

Авторы могут это сделать, но на самом деле это кажется более «нестандартным», чем просто использование свойств JS. Это также может вызвать странные проблемы, связанные с синтаксическим анализом и клонированием элемента .

React должен согласиться с тем, что если автор настраиваемого элемента хочет, чтобы настраиваемый элемент работал со всеми возможными библиотеками, а не только с React, то этот автор будет полагаться на setAttribute, чтобы сделать его элемент по умолчанию совместимым со всем, и если по умолчанию все библиотеки полагаются на атрибуты , тогда вся вселенная будет работать друг с другом. В этом нет никаких «если», «а» или «но»! (если w3c / whatwg не внесет больших изменений)

Я не уверен, как вы пришли к такому выводу, потому что есть другие библиотеки, которые предпочитают устанавливать свойства JS для пользовательских элементов (например, Angular). Для максимальной совместимости авторы должны поддерживать свои атрибуты с помощью свойств JS. Это покроет самую большую площадь возможного использования. Все элементы, созданные с помощью Polymer, делают это по умолчанию.

разрешить атрибутам работать 100% времени по умолчанию. Это означает, что должен по умолчанию отображаться на setAttribute и передавать значение без изменений. Это неизменное изменение. Фактически, это исправляющее изменение, которое в противном случае привело бы к передаче бессмысленной строки «[object Object]».

Я думаю, что React на самом деле _is_ передает значение без изменений. Вызов setAttribute('foo', {some: object}) приводит к [object Object] . Если только вы не предлагаете, чтобы они назвали объект JSON.stringify() ? Но тогда этот объект не «неизменен». Я думаю, может быть, вы полагаетесь на то, что автор переопределил setAttribute() ? Более правдоподобным было бы побудить их создавать соответствующие свойства JS вместо того, чтобы обезьяны исправлять DOM.

Я думаю, что React на самом деле _is_ передает значение без изменений. Вызов setAttribute('foo', {some: object}) приводит к [object Object]

React приводит значения к строке перед передачей в setAttribute :

https://github.com/facebook/react/blob/4d6540893809cbecb5d7490a77ec7ad32e2aeeb3/packages/react-dom/src/client/DOMPropertyOperations.js#L136

а также

https://github.com/facebook/react/blob/4d6540893809cbecb5d7490a77ec7ad32e2aeeb3/packages/react-dom/src/client/DOMPropertyOperations.js#L166

Я в основном согласен со всем, что вы сказали.

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

  • Вариант 3 с setAttribute используемым по умолчанию, и сигилом для указания использования свойств экземпляра,
  • с исправлением для # 10070, чтобы React не приводил аргументы к строкам,
  • и вариант 5, API для точной настройки

Если вариант 5 выполнен правильно, то гидратация для решений SSR может сопоставлять данные либо с атрибутами, либо с реквизитами, что может быть указано с помощью API варианта 5.

React приводит значения к строке перед передачей в setAttribute

Понятно. Поскольку большинство людей не определяют пользовательский toString() умолчанию используется [object Object] .

Поскольку большинство людей не определяют пользовательский toString() умолчанию используется [object Object] .

Так же, как если бы я

const div = document.createElement('div')
div.setAttribute('foo', {a:1, b:2, c:3})

результат

<div foo="[object Object]"></div>

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

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

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

@sebmarkbage Извините, я вовсе не хотел быть язвительным, и я думаю, что React - хорошая библиотека. Я должен был там более внимательно обдумать свои слова (особенно потому, что не все исповедуют одну и ту же религию).

Я имел в виду, что React очень популярен, поэтому React может побудить людей делать что-то определенным образом, который может не работать в других местах (например, он может сказать людям полагаться на свойства экземпляра для всех настраиваемых элементов, которые не будут работать). t работает со всеми пользовательскими элементами).

В настоящее время React преобразует все значения, переданные в атрибуты элемента, в строки. Если бы React не сделал этого, например, не было бы необходимости даже в существовании aframe-response (который работает с проблемой строки).

Если бы React мог просто позволить нам делать любой выбор в отношении того, как мы передавать данные элементам, как в обычном JavaScript, это сделало бы меня самым довольным пользователем. 😊

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

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

Я очень хочу, чтобы эта функция была реализована в React. Большое спасибо за ваши усилия по созданию отличного React.

Есть какие-нибудь обновления по этому RFC?

Библиотеки пользовательских элементов становятся действительно хорошими, и я хотел бы использовать их в своем приложении React. Есть новости по этому поводу? Обертывание пользовательских элементов и преобразование их содержимого в строку для последующего их повторного анализа - довольно неработающее решение, учитывая, что Vue и Angular легко обрабатывают компоненты изначально.

Есть новости по этой проблеме?

Я тоже хотел бы использовать библиотеки пользовательских элементов, не прибегая к хитростям. Я бы хотел, чтобы эта проблема была решена.

Команда @ mgolub2 React не заботится о том, чего хочет веб-сообщество. Веб-компоненты в настоящее время являются широко поддерживаемым стандартом, и через 2 года от команды не поступило никаких сигналов о поддержке этого стандарта.

Привет всем, я начал запрос на перенос, чтобы исправить эту проблему, изменив две строки: https://github.com/facebook/react/pull/16899

Это позволяет автору настраиваемого элемента делать что-то вроде следующего:

class MyElement extends HTMLElement {
  setAttribute(name, value) {
    // default to existing behavior with strings
    if (typeof value === 'string')
      return super.setAttribute(name, value)

    // but now a custom element author can decide what to do with non-string values.
    if (value instanceof SomeCoolObject) { /*...*/ }
  }
}

Существует множество вариантов того, как может выглядеть расширенный метод setAttribute , это всего лишь один небольшой пример.

Команда React, вы можете возразить, что авторы настраиваемых элементов не должны этого делать, потому что в некоторых случаях они обходят встроенную обработку атрибутов DOM (например, когда значения не являются строками). Если у вас есть такое мнение, это еще не означает, что вы должны препятствовать тому, что авторы настраиваемых элементов могут делать со своими элементами __ custom __.

React не должен высказывать мнение о том, как используются существующие DOM API. React - это инструмент для манипулирования DOM, и не следует высказывать мнение о том, что мы можем сделать с DOM, а только о том, каким образом данные поступают в DOM. Под «способом передачи данных в DOM» я подразумеваю маршрут, по которому данные попадают туда без изменения данных (преобразование объектов автора в строки изменяет данные автора).

Почему вы хотите видоизменить данные автора? Почему вы не можете просто предположить, что человек, который хочет манипулировать DOM, знает, какие данные передать в DOM?

@trusktr Я думаю, это обсуждалось в https://github.com/facebook/react/issues/10070

Я бы действительно предостерегал людей от того, чтобы указывать авторам настраиваемых элементов переопределять встроенный метод вроде setAttribute . Я не думаю, что это предназначено для нас, чтобы обезьяны исправлять это. cc @gaearon

Безобидно переопределить setAttribute в таких подклассах (это не исправление обезьяны). Но, как я уже упоминал, почему React должен это диктовать, если это не обязательно работа библиотеки React. Мы хотим использовать React для управления DOM (без помех).

Если мне приходится использовать el.setAttribute() вручную для повышения производительности, это также ухудшает опыт разработчика.

Я не думаю, что команда React спасает многих людей от какой-то огромной опасности, конвертируя все, что передается в setAttribute в строки.

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

Что потеряет сообщество, если мы уберем автоматическое преобразование строк? Что теряет команда React?

Команда React могла бы исправить ситуацию позже, используя лучшее решение ...

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

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

Можете ли вы объяснить, почему?

Это похоже на отвлекающий маневр. «Убедить всех, кто пишет пользовательские элементы, прикрепить к их элементу метод с определенным поведением» - не решение этой проблемы, которая касается того, как устанавливать свойства для элементов DOM.

@trusktr

Можете ли вы объяснить, почему?

Веб-компоненты являются стандартом. Таким образом, производные от стандарта также должны соответствовать стандарту.

Однако переопределение setAttribute не соответствует этому условию: оно создает взлом только для React, в то время как существует множество других фреймворков, которые работают с веб-компонентами из коробки. Таким образом, им нужно будет использовать хак React, даже если они вообще не работают с React. Не думаю, что это правильное решение.

Далее, хорошо известно, что исправление стандартных методов - неправильный подход. Переопределение setAttribute изменяет исходное поведение, которое может запутать конечных пользователей, когда они попытаются его использовать. Все ожидают, что стандарт будет работать как стандарт, и пользовательский элемент не является исключением, потому что он наследует поведение HTMLElement . И хотя он может работать с React, он создает ловушку для всех остальных пользователей. Например, когда веб-компоненты используются без фреймворка, setAttribute может вызываться много. Я сомневаюсь, что разработчики кастомных элементов согласились бы на такой подход.

Лично я считаю, что какая-то оболочка React выглядит более многообещающей.

Привет, ребята, пока мы ждем, я создал прокладку для упаковки вашего веб-компонента в React https://www.npmjs.com/package/reactify-wc

import React from "react";
import reactifyWc from "reactify-wc";

// Import your web component. This one defines a tag called 'vaadin-button'
import "@vaadin/vaadin-button";

const onClick = () => console.log('hello world');

const VaadinButton = reactifyWc("vaadin-button");

export const MyReactComponent = () => (
  <>
    <h1>Hello world</h1>
    <VaadinButton onClick={onClick}>
      Click me!
    </VaadinButton>
  </>
)

Надеюсь, это окажется полезным

(Это мой первый набег на OSS и один из первых открытых исходников чего-то вне моего офиса. Конструктивная критика более чем приветствуется 😄)

Привет, ребята, пока мы ждем, я создал прокладку для упаковки вашего веб-компонента в React https://www.npmjs.com/package/reactify-wc

import React from "react";
import reactifyWc from "reactify-wc";

// Import your web component. This one defines a tag called 'vaadin-button'
import "@vaadin/vaadin-button";

const onClick = () => console.log('hello world');

const VaadinButton = reactifyWc("vaadin-button");

export const MyReactComponent = () => (
  <>
    <h1>Hello world</h1>
    <VaadinButton onClick={onClick}>
      Click me!
    </VaadinButton>
  </>
)

Надеюсь, это окажется полезным

(Это мой первый набег на OSS и один из первых открытых исходников чего-то вне моего офиса. Конструктивная критика более чем приветствуется 😄)

Отличная обертка :)

Также стоит отметить, что создание веб-компонентов с помощью Stencil устраняет эту проблему с помощью React: https://stenciljs.com/docs/faq#can -data-be-pass-to-web-components-

@matsgm Я рад, что

Просто пытаюсь быть в курсе этой темы. Какое окончательное решение?

В некотором смысле я большой поклонник явного определения attr, prop, event, а не магической эвристики, что может сбивать с толку.

Например, snabbdom использует явное пространство имен верхнего уровня, что позволяет легко узнать, что и куда идет. Нет операций со строкой, которые выполняются быстрее, например, обрезка суффикса из onClick => click по-прежнему является перфомансом.

<input attrs={{placeholder: `heyo`}} style={{color: `inherit`}} class={{hello: true, world: false}} on={{click: this.handleClick}} props={{value: `blah`}} />
attr = (attr, val) => elem.setAttribute(attr, val);
prop = (prop, val) => elem[prop] = val;
on  = (event, handler) => elem.addEventListener(event, handler)
style = (prop, val) => elem.style[prop] = val;
class = (name, isSet) => isSet ? elem.classList.add(name) : elem.classList.remove(val)
dataset = (key, val) => elem.dataset[key] = val;

Я бы хотел, чтобы JSX поддерживал пространство имен с точечным синтаксисом. Это означает, что props будет пространством имен по умолчанию, и мы могли бы просто написать

<div tabIndex={-1} attr.title={"abcd"} on.click={handler} style.opacity={1} class.world={true} />`

fyi @sebmarkbage ^

const whatever = 'Whatever';
const obj = { a: 1, b: 2 };
const reactComponent = (props) => (
<div>
  ...
  <custom-element attr="{whatever}" someProp={obj} />
  { /* double quotes for attributes */ }
  { /* no quotes for properties */ }
</div>
);

Этого можно достичь, изменив парсер React JSX Pragma.

Дополнительный вариант - оставить propeties (или props для фанатов реакции) в качестве обозначенного слова для передачи собственности.

Поскольку 17.0 была выпущена сегодня, можем ли мы обновить эту проблему, чтобы отразить статус того, когда она будет решена?

Ага. Изначально мы планировали, что React 17 будет выпуском, в котором будет удалено гораздо больше устаревших функций (и с новыми функциями). Однако для старых кодовых баз не очень реалистично обновлять весь свой код, и поэтому мы решили выпустить React 17, который фокусируется только на одном значительном критическом изменении (события прикрепляются к корневому элементу, а не к документу ). Это сделано для того, чтобы старые приложения могли оставаться на React 17 навсегда и обновлять только их часть до 18+.

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

Я не уверен, каков последний консенсус сообщества WC относительно того, какой из этих вариантов предпочтительнее. Тем не менее, очень полезно записать их все (большое спасибо @robdodson за эту работу). Мне любопытно, изменилось ли мнение людей об этих вариантах с момента написания этой ветки, и есть ли какая-либо новая информация, которая могла бы помочь нам выбрать направление.

Я не думаю, что сообщество WC изменило свой предпочтительный вариант, который по-прежнему остается вариантом 3. @developit может больше рассказать о том, как Preact совместим с пользовательскими элементами, что также может быть интересно для React. Для общего обзора совместимости фреймворков с передачей (сложных) данных в пользовательские элементы https://custom-elements-everywhere.com/ содержит все подробности.

Обратите внимание, что в https://github.com/vuejs/vue/issues/7582 Vue решил использовать сигил, а они выбрали "." в качестве префикса (не "@" у Glimmer).

В https://github.com/vuejs/vue/issues/7582#issuecomment -362943450 @trusktr предположил, что наиболее правильной реализацией SSR было бы не отображать свойства sigil'd как атрибуты в SSR'd HTML, а вместо этого установите их как свойства через JS во время гидратации.

Я думаю, маловероятно, что мы введем новый синтаксис JSX только ради этой конкретной функции.

Также возникает вопрос, стоит ли использовать вариант (3), если на столе, возможно, имеется более общая версия варианта (5). То есть опция (5) может быть низкоуровневым механизмом для объявления настраиваемых низкоуровневых узлов React с настраиваемым поведением при монтировании / обновлении / отключении / гидратации. Даже не для специальных элементов как таковых (хотя они могут быть одним из вариантов использования).

Вместо того, чтобы вводить полностью новый синтаксис JSX для этой конкретной функции, как насчет введения более общего JSX и его использования для определения настраиваемых свойств?

Я уже давно предложил добавить синтаксис вычисляемых свойств ECMAScript в JSX (facebook / jsx # 108) и думаю, что это будет полезным дополнением к синтаксису в целом.

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

Например:

import {property} from 'react';
// ...
<custom-img [property('src')]="corgi.jpg" [property('hiResSrc')]="[email protected]" width="100%">

@dantman Как это предложение обрабатывает рендеринг и гидратацию сервера?

Я не думаю, что кто-то в сообществе WC хочет вариант 5.

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

Что вы думаете о серверном рендеринге и гидратации? Если нет явной конфигурации, какая эвристика желательна? Произошла ли консолидация в том, как это обычно делается в сообществе WC? Я перечитал этот RFC, и, похоже, он не вдавался в подробности по этой теме. Но это очень важно, особенно когда React делает больший упор на серверный рендеринг (поскольку его часто справедливо критикуют за слишком клиентоцентричные настройки по умолчанию).

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

Общая идея состоит в том, что property(propertyName) может, в зависимости от того, как вы хотите его реализовать, вывести строку с префиксом (например, '__REACT_INTERNAL_PROP__$' + propertyName ) или создать символ и сохранить ассоциацию "symbol => propertyName" в карта.

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

Однако, насколько я понимаю, свойства - это не то, что вы можете обрабатывать на сервере, а гидратация включает в себя клиентский код, поэтому я не уверен, каков план для этого. Что касается моего предложения, его, вероятно, можно адаптировать к любым планам, которые у вас есть для решения этой проблемы. Если вы планируете что-то реагировать на свойства на сервере, он может просто сделать это, когда увидит одно из свойств, созданных property .

Для автора библиотеки веб-компонентов вариант 5 - неудобный выбор. Я хочу создавать собственные элементы без явного определения схемы для каждой платформы и компонента. И многие авторы настраиваемых элементов просто не будут этого делать, перекладывая бремя на разработчика React.

Никто не выигрывает с вариантом 5. 😕

@claviska Есть ли у вас какие-либо мнения о том, как серверный рендеринг и гидратация должны работать с более неявными подходами?

@gaearon SSR подразделяется на две ситуации: те, где настраиваемый элемент поддерживает SSR, и те, где это не так.

Для элементов, которые не поддерживают SSR, установка свойств на сервере не имеет значения. За исключением встроенных отражающих свойств, таких как id и className , их можно отбросить и записать только на клиенте.

Для элементов, которые действительно поддерживают свойства SSR, будут иметь значение, но только для того, чтобы они могли запускать любой результат, который они вызывают в DOM. Для этого требуется экземпляр элемента или какой-то прокси / заместитель SSR и некоторый протокол для передачи состояния DOM, связанного с SSR. Общего серверного интерфейса для этого процесса пока нет, так что тут действительно ничего не поделаешь. Авторам веб-компонентов и разработчикам библиотек нужно будет кое-что выяснить, прежде чем React сможет навести там какие-либо мосты.

В моей команде, работающей над SSR, мы интегрировались с React, исправив createElement и используя dangerouslySetInnerHTML . Я думаю, что это тот уровень интеграции / экспериментирования, на котором мы будем некоторое время. Я надеюсь, что в какой-то момент скоро мы сможем объединиться на некоторых пользовательских протоколах для взаимодействия с системами SSR. До тех пор совершенно безопасно и разумно иметь настраиваемые свойства элемента и поддержку событий без _deep_ SSR. Тег элемента по-прежнему будет SSR'ed как дочерний компонент React-компонента, как и сегодня.

За исключением встроенных отражающих свойств, таких как id и className, их можно отбросить и записать только на клиенте.

Вы можете помочь мне понять, как это работает? Скажем, есть <github-icon iconname="smiley" /> . Вы имеете в виду, что SSR должен просто включать <github-icon /> в ответ HTML, а затем React установит domNode.iconname = ... во время гидратации? В этом случае я не уверен, что понимаю, что произойдет, если реализация настраиваемого элемента загрузится до того, как произойдет гидратация React. Как реализация github-icon узнает, какой значок отображать, если iconname не существует в HTML?

Общего серверного интерфейса для этого процесса пока нет, так что тут действительно ничего не поделаешь. Авторам веб-компонентов и разработчикам библиотек нужно будет кое-что выяснить, прежде чем React сможет навести там какие-либо мосты.

Мне любопытно, должно ли произойти что-то конкретное, чтобы сообщество сформировало здесь консенсус. React сдерживает это? Я очень понимаю разочарование, связанное с тем, что этот вопрос открыт с 2017 года. С другой стороны, прошло три года, и я думаю, вы говорите, что этот консенсус еще не сформирован. Какие предпосылки для этого? Это просто вопрос дополнительных экспериментов?

@gaearon, если реализация пользовательского элемента загружается до того, как произойдет гидратация React, он назначит любое значение по умолчанию для атрибута iconname . Что вы имеете в виду под if _iconname_ does not exist in the HTML ? Если для типа HTMLElement не определен атрибут, он его проигнорирует. после загрузки определения настраиваемого элемента он расширит тип HTMLElement и определит iconname и сможет реагировать на новое передаваемое значение.

Я пытаюсь понять это с точки зрения пользователя. Мы рендерим страницу на сервере. У него есть значок в середине текста. Этот значок реализован как настраиваемый элемент. Какую последовательность вещей должен испытывать конечный пользователь?

На данный момент я понимаю, что:

  1. Они видят первоначальный результат рендеринга. Он будет включать всю обычную разметку, но пользовательский элемент <github-icon> они не увидят вообще. Предположительно это будет дыра, как пустой div. Пожалуйста, поправьте меня, если я ошибаюсь (?). Его реализация еще не загружена.

  2. Реализация пользовательского элемента <github-icon> загружается и регистрируется. Если я правильно понял, это процесс, который называется «апгрейд». Однако, хотя его JS готов, он по-прежнему ничего не может показать, потому что мы не включили iconname в HTML. Итак, у нас нет информации о том, какой значок отображать. Это потому, что мы говорили ранее, что «невстроенные свойства могут быть удалены из HTML». Так что пользователь все равно видит «дыру».

  3. React, и код приложения загрузится. Происходит гидратация. Во время гидратации React устанавливает свойство .iconname = в соответствии с эвристикой. Теперь пользователь может видеть значок.

Это правильная разбивка для случая, когда сначала загружается реализация JS пользовательского элемента? Желательно ли такое поведение для сообщества WC?

@gaearon да, именно этого я и ожидал в этой ситуации.

С другой стороны, прошло три года, и я думаю, вы говорите, что этот консенсус еще не сформировался.

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

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

Под «глубоким» SSR, я думаю, вы имеете в виду SSR, похожий на то, как он работает в компонентах React. То есть рендеринг CE приведет к получению вывода, который можно отобразить до загрузки логики CE. Вы говорите, что нам не следует беспокоиться о поддержке сейчас. Это имеет смысл для меня.

Под «неглубоким» SSR, я думаю, вы говорите, что мы просто помещаем сам тег CE в HTML. Не беспокоясь о том, к чему это приведет. Для меня это тоже имеет смысл. Мой вопрос был об этом потоке, а не о "глубоком" SSR.

В частности, https://github.com/facebook/react/issues/11347#issuecomment -713230572 описывает ситуацию, когда даже когда мы _ уже загрузили_ логику CE, мы по-прежнему не можем ничего показать пользователю до гидратации. Становится неизвестными его свойства до тех пор, пока не загрузится клиентский код JS всего приложения и не произойдет гидратация. Я спрашиваю, действительно ли это желаемое поведение.

Я не думаю, что с моей точки зрения это смутное беспокойство. Я не хочу неправильно понять запрос функции. Таким образом, точная указанная семантика поможет мне оценить это предложение. Например, одна практическая проблема заключается в том, что React фактически не различает атрибуты / свойства в производстве во время гидратации сегодня, потому что ни один из встроенных компонентов не нуждается в этом. Но это то, что мы могли бы добавить для этого конкретного случая, если это действительно необходимо.

@gaearon

Я думаю, что https://github.com/facebook/react/issues/11347#issuecomment -713230572 может быть не лучшим примером, в котором эта функция необходима.

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

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

Вреализация настраиваемого элемента загружается и регистрируется. Если я правильно понял, это процесс, который называется «апгрейд». Однако, несмотря на то, что его JS готов, он по-прежнему ничего не может показать, потому что мы не включили имя значка в HTML. Итак, у нас нет информации о том, какой значок отображать. Это потому, что мы говорили ранее, что «невстроенные свойства могут быть удалены из HTML». Так что пользователь все равно видит «дыру».

Что касается того, что вы здесь упомянули, в зависимости от того, как реализован компонент, вы можете избежать этой проблемы, связанной с появлением «дыры».

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


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

Возьмем, к примеру, компонент виртуального скроллера lit-virtualizer .

Для этого , чтобы работать должным образом, она требует items массива и renderItem функции , и вы можете даже необязательно установить scrollTarget Element, все из которых может быть установлен только в React с помощью рефов Сейчас.

В таком случае вы, вероятно, все равно загружаете контент с какой-либо разбивкой на страницы или ленивой загрузкой, поэтому отсутствие какого-либо контента до этапа гидратации в случае SSR может не быть такой проблемой.

@gaearon Обратите внимание, что пользовательские элементы являются стандартом DOM и, следовательно, не существует как такового «сообщества WC» в том смысле, что каждый, кто использует пользовательские элементы, использует их одинаково. Пользовательские элементы интегрируются по-своему для каждого разработчика, поскольку они по своей сути являются примитивами низкого уровня, на которых люди строят.

Тем не менее, со временем появилось множество шаблонов, и все популярные фреймворки (кроме React) реализуют какое-либо решение для обеспечения совместимости с этим стандартом DOM. Как вы можете видеть на https://custom-elements-everywhere.com/ , все фреймворки / библиотеки (кроме React) выбрали разные варианты. В этом выпуске выбранные параметры перечислены как варианты 1, 2 и 3. В настоящее время нет фреймворка / библиотеки, которые реализуют вариант 4 или 5, и я не думаю, что их следует реализовывать.

Поэтому я предлагаю, чтобы React последовал примеру других фреймворков / библиотек и выбрал вариант, который доказал свою эффективность, например, из вариантов 1-3. Я не думаю, что React нужно изобретать велосипед здесь, выбирая вариант 4 или 5, по которым у нас нет данных, это долгосрочное поддерживаемое решение либо для React, либо для тех, которые основаны на стандартах DOM.

Итак, в процессе исключения (с комментариями, приведенными ниже), поскольку вариант 3 не будет применяться к JSX, а варианты 4 и 5 были отмечены людьми из WC в этой ветке как нежелательные, мы застряли с 1 или 2 .

И поскольку 1 кажется, что у него есть несостоятельные недостатки, похоже, что вариант 2 - это тот? Просто посмотрим, как это делает Preact?


В настоящее время нет фреймворка / библиотеки, которые реализуют вариант 4 или 5, и я не думаю, что их нужно реализовывать.

( @TimvdLippe в https://github.com/facebook/react/issues/11347#issuecomment-713474037)

Я думаю, маловероятно, что мы введем новый синтаксис JSX только ради этой конкретной функции.

( @gaearon в https://github.com/facebook/react/issues/11347#issuecomment-713210204)

Для меня это имело бы смысл, да. Спасибо за резюме! 😄

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

Я не совсем понимаю. Мой гипотетический сценарий был ответом на https://github.com/facebook/react/issues/11347#issuecomment -713223628, который звучал как предложение о том, что мы вообще не должны генерировать атрибуты в сгенерированном сервером HTML, за исключением id и class . Я не знаю, что означает «просто использовать имя значка в качестве атрибута» - вы говорите, что хотели бы видеть сгенерированные сервером HTML _include_ другие атрибуты? Похоже, это противоречит тому, что было только что сказано ранее. Я думаю, что было бы действительно полезно, если бы каждый ответ представлял полную картину, потому что в противном случае мы будем продолжать ходить по кругу. Мой вопрос к вам:

  1. Что именно сериализуется в сгенерированном сервером HTML в описанном мной сценарии
    а. В случае <github-icon iconname="smiley" />
    б. В случае, если вы подняли, например, <github-icon icon={{ name: "smiley" }} />
  2. Какой DOM API вызывается на клиенте во время гидратации в любом из этих случаев

Спасибо!

Рассматривался ли вариант создания прокладки, заменяющей React.createElement() пользовательской реализацией, которая выполняет отображение свойств внутри?

Пример использования:

/** <strong i="8">@jsx</strong> h */
import { h } from 'react-wc-jsx-shim';

function Demo({ items }) {
   return <my-custom-list items={items} />
}

Проект реализации:

export function h(element, props, children) {
   if(typeof element === 'string' && element.includes('-')) {
      return React.createElement(Wrapper, { props, customElementName: element }, children)
   }
   return React.createElement(element, props, children);

}

function Wrapper({customElementName, props}) {
   const ref = React.useRef();
   React.useEffect(() => {
      for(const prop in props) {
         ref.current[prop] = props[prop];
      }
   });
   return React.createElement(customElementName, { ref, ...props });
}

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

@ just-boris это в основном то, что сейчас делают приложения или библиотеки, с патчем createElement или оболочкой. Вам также необходимо исключить имена свойств в специальном регистре в React. Я не думаю, что существует экспортированный список, поэтому они просто жестко кодируют денилист, например ['children', 'localName', 'ref', 'elementRef', 'style', 'className'] .

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

На самом деле я был бы больше озабочен событиями, чем SSR. В React нет возможности добавлять обработчики событий, и это огромная дыра во взаимодействии с базовыми API-интерфейсами DOM.

Рассматривался ли вариант создания прокладки, заменяющей React.createElement () пользовательской реализацией, которая выполняет отображение свойств внутри?

Как упоминал Роб в исходном выпуске, я экспериментировал с этим в прошлом через https://github.com/skatejs/val , поэтому наличие пользовательской прагмы JSX, которая обертывает React.createElement является жизнеспособным - возможно, краткосрочный - решение.

У меня также есть WIP-ветка Skate, реализующая то, что называется глубоким и поверхностным SSR, специально для React. Выводы из этой работы до сих пор заключаются в том, что у вас не может быть единой оболочки JSX для всех библиотек, если вы хотите делать глубокий SSR, потому что каждая библиотека зависит от своих собственных API-интерфейсов и алгоритмов для этого. (Для контекста, у Skate есть основная часть пользовательских элементов в своей библиотеке и небольшие слои, созданные для интеграции каждой популярной библиотеки на рынке, чтобы сделать потребление и использование единообразным по всем направлениям.)


Я больше не работаю с открытым исходным кодом и не использую Twitter, так что не стесняйтесь относиться к моему мнению с долей скептицизма.

Вариант 1 кажется, что он существует как адвокат дьявола для Варианта 2.

Вариант 2 кажется подходящим. Это близко к тому, что было сделано в Preact, поэтому есть прецедент и возможность стандарта сообщества (что, я думаю, было бы фантастически сделать в любом случае; JSX показал, что это может работать), и это также прагматичный шаг для React, заключающийся в простоте обновления. (в отличие от Варианта 1).

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

Как уже упоминалось, я изначально представил вариант 4, но после размышлений я не уверен, что он мне больше нравится. Вы можете изменить его так, чтобы он был более добровольным, где вы явно указываете props и events (вместо attrs ), но даже тогда для варианта 2 требуется меньше знаний о деталях реализации. и никому не нужно ничего менять, чтобы принять его.

Вариант 5 выглядит так, как будто мы полностью игнорируем основную проблему.


В стороне, я очень рад видеть успех в этом и надеюсь, что у вас все хорошо!

Если в пользовательском пространстве есть возможное решение, может ли оно быть консолидировано и рекомендовано сообществом на данный момент?

Было бы намного проще убедить основную команду React добавить функцию, если она уже существует как популярный и жизнеспособный сторонний модуль.

Если в пользовательском пространстве есть возможное решение, может ли оно быть консолидировано и рекомендовано сообществом на данный момент?

Я не верю, что это можно [аккуратно] исправить снаружи. Большинство пользовательских решений - это такие обертки, как this и this . Без модификации React я не могу придумать разумной альтернативы этому подходу, и упаковка определенно не является идеальным решением. 😕

Обратите внимание, что в vuejs / vue # 7582 Vue решил использовать сигил, и они выбрали "." в качестве префикса (не "@" у Glimmer).

У меня нет ссылки на авторитетное заявление по этому поводу (и, возможно, кто-то, кто ближе к Vue, может явно подтвердить), но похоже, что Vue перешел на вариант 2 с Vue 3.0, что означает, что он ведет себя аналогично Preact. (См. Контекст в этой проблеме .)

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

Не могли бы вы ответить на конкретные вопросы в https://github.com/facebook/react/issues/11347#issuecomment -713514984? Я чувствую, что мы говорим мимо друг друга. Я просто хочу понять предполагаемое поведение целиком - определенным образом. Что устанавливается, когда и что сериализуется, и в этом случае.

Как случайный разработчик Preact + WC, который здесь наткнулся, я хотел указать, что «Вариант 2» - это не только _ критическое изменение_, но и _ неполное решение_ (Preact все еще может взаимодействовать только декларативно с подмножеством допустимых веб-компонентов).

Даже для текущего пользователя эвристики это звучит вряд ли желательно в долгосрочной перспективе.


Эвристика Preact («вариант 2») не может устанавливать свойства, которые имеют особое значение в React (ключ, дочерние элементы и т. Д.) Или Preact (все, что начинается с on ).

Т.е. после рендеринга ниже JSX:

<web-component key={'key'} ongoing={true} children={[1, 2]} />

properties key , ongoing и children будут иметь значение undefined (или любое другое значение по умолчанию) в созданном экземпляре web-component .

Кроме того, в отличие от OP, этот вариант также является критическим изменением. Большинство веб-компонентов (например, созданных с помощью lit-element ) предлагают возможность передавать сериализованные расширенные данные через атрибуты для использования с чистым HTML. Такие компоненты можно рендерить из React так:

<web-component richdata={JSON.stringify(something)} />

который сломается, если будет выбран «вариант 2». Не уверен, насколько распространено такое использование веб-компонентов в React, но определенно есть некоторые кодовые базы, которые делают это, он менее эффективен, чем ссылки, но также более сжат.

И, наконец, автор веб-компонента может добавить несколько отличающуюся семантику к атрибуту и ​​свойству с тем же именем. Примером может служить веб-компонент, имитирующий поведение собственного элемента input - обрабатывающий атрибут value как начальное значение и наблюдающий только за изменениями в свойстве value . С такими компонентами невозможно полностью взаимодействовать через jsx с помощью эвристического подхода, а также могут возникнуть небольшие поломки, если они будут введены.

Я думаю, маловероятно, что мы введем новый синтаксис JSX только ради этой конкретной функции.

А как насчет использования пространств имен? https://github.com/facebook/jsx/issues/66 предлагает добавить пространство имен react для key и ref . В том же духе, может ли что-то вроде react-dom быть подходящим пространством имен, которое можно использовать для идентификации свойств DOM? Используя пример варианта 3 OP, это будет:

<custom-img react-dom:src="corgi.jpg" react-dom:hiResSrc="[email protected]" width="100%">

Это не самое эргономичное. Просто dom было бы лучше, но не уверен, что React хочет создавать пространства имен, которые не начинаются с react . Кроме того, плохая эргономика здесь не конец света, если идея состоит в том, что установка свойств должна быть менее распространенным случаем. Лучше использовать атрибуты, поскольку это обеспечивает равенство с SSR. Установка в качестве свойств предназначена для случаев, когда атрибуты проблематичны (например, для передачи объекта или для свойств, не поддерживаемых атрибутами), и именно для этих проблемных свойств мы все равно не можем применить SSR к атрибутам и должны будут их гидратировать. через JS.

_ неполное решение_

(Preact все еще может декларативно взаимодействовать только с подмножеством действительных веб-компонентов)

@brainlessbadger, можете ли вы также отредактировать свой комментарий выше, чтобы включить, что это за подмножество на самом деле? Например. какие веб-компоненты / пользовательские элементы затронуты (с примерами)? И как именно на них влияют?

@karlhorky Я добавил пояснение. Извините за излишнюю расплывчатость.

Что касается событий веб-компонентов. Есть ли консенсус по поводу того, как избежать блокировки в будущем путем совпадения названий событий?

Это также проблема для атрибутов и свойств, поскольку новые атрибуты могут быть добавлены в HTMLElement, как и все эти: https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes Похоже, есть несколько недавно добавленные, так что есть еще добавляемые.

Я думаю, строго говоря, вы должны использовать - в имени любого настраиваемого атрибута или настраиваемого события.

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

События заставляют меня нервничать, потому что это не просто риск того, что этот компонент будет иметь несовместимое поведение. Если новое событие всплывает, оно запускает все существующие веб-компоненты в этом древовидном пути.

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

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

Я думаю, что, строго говоря, вам следует использовать - в имени любого настраиваемого атрибута или настраиваемого события.

Спецификация настраиваемого элемента не включает таких ограничений, поэтому их соблюдение в React существенно повлияет на совместимость.

От авторов настраиваемых элементов не следует ожидать, что они будут подписываться на произвольные требования фреймворка. Представьте, что каждая структура делает это с разными мнениями и соглашениями. Это противоречит цели использования веб-компонентов. 😕

В идеале структура должна адаптироваться к стандарту.

Действительно. setAttribute() и dispatchEvent() - это просто API-интерфейсы, не относящиеся к веб-компонентам, которые с момента их создания допускают произвольные имена. Любой элемент может иметь любой атрибут и запускать любое событие - это просто истина DOM.

Однако пространство имен data- было добавлено по какой-то причине. Есть разница между тем, что вы можете делать технически, и лучшими практиками. Вы также можете технически патчить прототипы, но тогда вы получите ситуации, содержащие / включающие.

Я бы не стал предлагать, чтобы это было просто добавлено React, но чтобы сообщество перешло на это соглашение, чтобы защитить будущее пространство имен. Мне просто жаль, что к этому вопросу не относятся серьезно. Но, возможно, Интернет обречен только добавлять неудобные имена новым API.

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

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

Предполагая, что дверь не закрыта по варианту 3, он имеет значительное преимущество перед вариантом 2, не указанным в минусах выше - проблема, которую я обнаружил с вариантом 2, заключается в том, что если библиотеки веб-компонентов загружаются асинхронно , preact может не знайте, что для неизвестного элемента "свойство" будет свойством. Поскольку он не находит свойство, существующее в неизвестном элементе, по умолчанию используется атрибут. Обходной вариант - не отображать этот компонент до тех пор, пока не будут загружены зависимые библиотеки веб-компонентов, что не очень элегантно (или идеально с точки зрения производительности). Поскольку моя группа использует asp.net, а не node.js, я на самом деле никогда не исследовал SSR, поэтому приведенные ниже наблюдения являются спекулятивными.

Я думаю, это хороший жест со стороны команды React, предлагающий выйти за рамки того, что поддерживают другие фреймворки (насколько мне известно), в том, что касается SSR, позволяя передавать свойства объекта во время первоначального рендеринга, что могло бы послужить пользователю лучше.

Я не знаю, констатирую ли я очевидное или нет, но я думаю, что есть некоторый консенсус с веб-компонентами, что для некоторых свойств удобно иногда устанавливать начальное значение атрибута через строку JSON , заключены в одинарные кавычки.

Однако AMP использует другое соглашение - для этого он использует script type = application.json , что является разумной (но многословной) альтернативой.

Но придерживаясь атрибутивного подхода:

Затем библиотека веб-компонентов может проанализировать атрибут или передать значение через свойство.

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

<github-icon icon='{"name":"smiley"}'></github-icon>

во время ССР. Тогда github-icon может немедленно сделать свое дело, внутренне выполнить JSON.parse атрибута и не ждать, пока React передаст (более полное?) Значение объекта.

Итак, теперь у нас возникла сложная ситуация - при рендеринге на сервере мы хотим, чтобы «значок» рассматривался как атрибут, но чтобы иметь возможность передавать значение как объект, который в идеале механизм SSR преобразовал бы в атрибут. На клиенте мы хотим иметь возможность передавать объект напрямую, а не тратить время на обработку строк и синтаксический анализ.

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

Если бы все свойства и атрибуты следовали предпочтительному соглашению об именах команды React (возможно) - все атрибуты имели тире, а все свойства были составными именами с использованием camelCase, возможно, наличие тире могло помочь различить атрибуты и свойства:

<github-icon my-icon={myStringifiedProperty} myIcon={myObjectProperty}></github-icon>

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

React может просто предположить, что если ключ атрибута / свойства является верблюжьим регистром, всегда передавать его как объект на стороне клиента и сериализацию объекта в виде строки в формате JSON, если он установлен во время SSR. Точно так же тире в ключе могут (я думаю, безопасно) предполагать, что это атрибут, и просто передавать .toString () значения. Но я думаю, это слишком многого. И отсутствие поддержки атрибутов и свойств из одного слова, который считается допустимым HTML, если атрибуты применяются к веб-компоненту, расширяющему HTMLElement, было бы слишком ограниченным. Я за то, чтобы W3C выпустил список «зарезервированных» имен атрибутов, которые он может использовать в будущем, аналогично зарезервированным ключевым словам для JS, и чтобы фреймворки находили способы предупреждать разработчиков, если они неправильно используют зарезервированное имя атрибута.

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

Мое предложение было бы:

<github-icon icon={myDynamicIcon}/>

означает атрибут (toString ()).

<github-icon icon:={myDynamicIcon}/>

будет означать - во время SSR игнорировать, но привязывать клиента к свойству объекта (после гидратации).

А что насчет сценария (некоторых из?), В решении которого заинтересована команда React? Моя первая мысль была просто какой-то другой сигилой, например, двумя двоеточиями:

<github-icon icon::={myDynamicIcon}/> //Not my final suggestion!

будет означать, что во время SSR JSON.stringify свойство, установленное как атрибут в визуализированном HTML, и передается как объект на клиенте, когда свойство, которое оно связывает, изменяется после гидратации.

Остается сложная ситуация с составными именами. Т.е. если мы установим:

<github-icon iconProps::={myDynamicIconProp}/>  //Not my final suggestion!

Раньше не было спорным, что соответствующий атрибут для имени свойства iconProps должен быть icon-props.

Возможно, это стало более спорным из-за предположения, что некоторые из этих веб-компонентов могут без изменений быть встроенными в платформу, где атрибуты не могут иметь дефисы (но свойства могут быть верблюжьими регистрами). Насколько мне известно, еще нет собственного элемента, который позволяет передавать сложные объекты через десериализацию JSON, но я не удивлюсь, если в будущем возникнет такая необходимость. Итак, как React узнает, когда вставлять тире или нет?

Единственное (уродливое?) Предложение, которое я могу придумать:

<github-icon icon-props:iconProps={myDynamicIconProp}/>

Это означает, что на сервере используйте атрибут icon-props после сериализации, а на клиенте используйте свойство iconProps, передавая объекты напрямую.

Еще одно (далеко идущее?) Потенциальное преимущество более подробной нотации, позволяющей использовать гибридную пару атрибут / свойство, заключается в следующем: может быть немного быстрее повторно устанавливать свойства собственного элемента, а не соответствующего атрибута, особенно для свойства, не являющиеся строками. Если да, то использует ли React в настоящее время атрибуты на сервере и свойства на клиенте? Если нет, то это из-за той же проблемы, связанной с трудностями перевода имен, которые эта нотация решила бы?

@bahrus я думаю это можно упростить

<my-element attr='using-quotes' property={thisIsAnObject} />

Думаю, лучше всего проиллюстрировать проблему на конкретном примере.

Элемент HTML Form имеет ряд атрибутов. Те, у которых есть "составные имена", не все, похоже, следуют единому шаблону именования - обычно он придерживается всех строчных букв, без разделителей, но иногда есть разделитель тире - например, "accept-charset", иногда нет - - "novalidate".

Соответствующее имя свойства JS тоже не вписывается в хороший универсальный шаблон - acceptCharset, noValidate. Свойство noValidate / атрибут novalidate является логическим, поэтому на клиенте было бы расточительно (я полагаю) выполнять myForm.setAttribute ('novalidate', '') в отличие от myForm.noValidate = true.

Однако на сервере нет смысла устанавливать myForm.noValidate = true, поскольку мы хотим отправить строковое представление DOM, поэтому нам нужно использовать атрибут:

<form novalidate={shouldNotValidate}>

На самом деле мне непонятно, имеет ли React / JSX универсальный способ условной установки логического атрибута , полагаясь, возможно, на фиксированную статическую таблицу поиска, которая кажется (?) Чрезмерно жесткой . Если я могу быть таким смелым, это похоже на то, что React / JSX может улучшить еще одну область, чтобы быть полностью совместимой с (беспорядочным) способом работы DOM в рамках этого RFC?

Как мы можем представить все эти сценарии, чтобы разработчик имел полный контроль над сервером (через атрибуты) и клиентом (через свойства) без ущерба для производительности? В этом случае логического значения, такого как novalidate, я бы предложил:

<form novalidate:noValidate?={shouldNotValidate}/>

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

Мне кажется, добавление поддержки для необязательной сериализации свойств объекта в атрибуты через JSON.stringify на сервере было бы дополнительным огромным беспроигрышным вариантом для React и веб-компонентов.

Или я что-то упускаю? ( @eavichay , как бы вы предложили лучше всего представить эти сценарии, не следуя вашему примеру).

Была ли эта страница полезной?
0 / 5 - 0 рейтинги