Полиморфный как опора в Astro

В Astro есть динамические теги — способ использовать элемент или компонент в качестве реквизита.

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

Динамические теги легко реализовать в Astro.

Реализация без суеты

  1. Возьмите заглавную Element опору в качестве локальной переменной.
  2. Отобразите этот реквизит как тег шаблона.
  3. Возьмите и разложите отдых-реквизит.
  4. Рендерите детей, используя безымянный <slot /> Astro.
---
const { Element, ...props } = Astro.props;
---
<Element {...props}><slot /></Element>

Деструктурируйте и переименуйте опорный элемент (для удобства или соглашения)

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

---
const { as: Element, ...props } = Astro.props;
---
<Element {...props}><slot /></Element>

Шаблоны Astro требуют, чтобы динамические теги были написаны с заглавной буквы. Переименование элемента — это общепринятый способ выполнить это требование, одновременно предоставляя потребителям более традиционный API.

Принимайте и устраняйте дубликаты классов с помощью class:list

В Astro есть директива class:list для управления динамическими классами. Предоставьте директиве class:list массив с классами provided и Component.

class:list умен и автоматически удаляет повторяющиеся классы.

---
const {
  as: Element = "div",
  class: providedProps,
  ...props
} = Astro.props;
const componentClasses = "prose prose-slate dark:prose-invert";
---
<Element {...props} class:list={[componentClasses, providedProps]}>
  <slot />
</Element>

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

В комплекте с интерфейсом TypeScript

Это мой готовый компонент с интерфейсом TypeScript.

Ваши потребности, вероятно, будут различаться.

---
interface Props {
  as?: "body" | "main" | "article";
  class?: "string";
}
const {
  as: Element = "div",
  class: providedProps,
  ...props
} = Astro.props;
---
<Element {...props} class:list={[componentClasses, providedProps]}>
  <slot />
</Element>

ВНИМАНИЕ: динамические теги не соблюдают директивы клиента гидратации.

Astro предоставляет клиентские директивы для оптимизации пользовательского интерфейса на стороне клиента. Они не работают с динамическими тегами.

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

Вынос

Astro поддерживает шаблон полиморфный как реквизит, популярный в React. А дополнительные стандартные инструменты TypeScript и директива class:list еще больше упрощают последовательную реализацию.