Svelte

Snippets: замена слотам

В таблице товаров одна и та же разметка ячейки повторяется десять раз, отличаясь лишь данными. Копировать её - значит плодить дубликат, который придётся править в десяти местах. В Svelte 5 кусок разметки оформляют как сниппет: блок {#snippet row(item)} объявляет его один раз, а {@render row(product)} вставляет с нужными данными. Сниппет принимает аргументы как функция, переиспользуется внутри компонента и передаётся в другой компонент как обычный проп. Так слоты Svelte 4 уступают место одному более гибкому механизму.

  • Строка таблицы, описанная сниппетом один раз и отрисованная для каждого товара
  • Компонент Card, принимающий сниппеты header и footer как пропсы оформления
  • Список с настраиваемым видом элемента: родитель передаёт сниппет, как рисовать каждый item
  • Модальное окно, куда контент передаётся через сниппет children
  • Таблица данных, которой передают сниппет рендера ячейки - паттерн render props

Предварительные знания

  • Синтаксис шаблонов: блоки each, if и фигурные скобки для выражений
  • Передача пропсов в компонент и чтение их через `$props`
  • Идея функции, которая принимает аргументы и возвращает результат

Почему слоты заменили на сниппеты

В Svelte 4 для вставки разметки снаружи использовались слоты: элемент slot в компоненте, именованные слоты через атрибут name, передача данных наверх через let-директивы. У слотов был отдельный синтаксис и ограничения: слот нельзя было передать как значение, переиспользовать или вызвать условно. Svelte 5 заменил их сниппетами - переиспользуемыми блоками разметки, которые ведут себя как функции. Сниппет можно объявить, отрисовать несколько раз, передать как проп и вызвать с аргументами. Один механизм покрыл всё, что делали слоты, и снял их ограничения.

Объявление и вставка сниппета

Сниппет объявляется блоком {#snippet name(...args)} и закрывается {/snippet}. Внутри лежит разметка, которая может использовать переданные аргументы. Чтобы отрисовать сниппет, его вызывают через {@render name(...args)}. Один сниппет рисуется сколько угодно раз с разными аргументами, поэтому повторяющаяся разметка описывается один раз и переиспользуется.

Сниппет row принимает item и описывает одну строку. Внутри блока each он вызывается для каждого товара через {@render row(product)}. Разметка строки задана единожды, а данные подставляются при каждом рендере. Изменить вид строки теперь можно в одном месте.

Сниппет виден в той области, где объявлен, по правилам областей видимости JavaScript. Сниппет, объявленный на верхнем уровне разметки, доступен во всём шаблоне. Сниппет внутри блока each виден только внутри этого блока.

Какая пара конструкций объявляет и отрисовывает сниппет?

Сниппеты как пропсы и render props

Сниппет - это значение, поэтому его передают в дочерний компонент как обычный проп. Дочерний компонент принимает сниппет через `$props` и отрисовывает его через {@render}, при этом передавая аргументы обратно. Так родитель решает, как выглядит элемент, а ребёнок - когда и с какими данными его нарисовать. Это паттерн render props: дочерний компонент управляет логикой, родитель управляет видом.

Компонент List ничего не знает о виде элемента: он перебирает data и для каждого вызывает переданный сниппет item, отдавая ему текущую запись. Родитель объявляет item и решает, что элемент - это жирный текст с именем. Один List подходит для любого вида элемента: список пользователей, товаров, сообщений.

Сниппет, переданный как атрибут с тем же именем, записывают сокращённо: вместо item равно item достаточно фигурных скобок с именем. Это та же сокращённая запись пропса, что и для обычных значений.

Что описывает паттерн render props через сниппеты?

Сниппет children и контент компонента

Разметка между открывающим и закрывающим тегами компонента автоматически становится сниппетом с именем children. Дочерний компонент читает children из `$props` и вставляет его через {@render children()}. Это прямая замена безымянного слота из Svelte 4 - типичный способ собрать обёртку вроде карточки или модального окна, внутрь которой кладут любой контент.

  • Слоты Svelte 4 — Безымянный slot и именованные слоты через name, передача данных через let-директивы. Отдельный синтаксис, слот нельзя переиспользовать или передать дальше
  • Сниппеты Svelte 5 — children для основного контента и именованные сниппеты-пропсы для остального. Единый механизм, сниппет - обычное значение

children - это сниппет, то есть функция, поэтому его вызывают через {@render children()} со скобками. Попытка вставить children как переменную без render не отрисует разметку. Скобки обязательны, как при вызове любого сниппета.

Откуда берётся сниппет children в дочернем компоненте?

Связь с другими темами

Сниппеты опираются на шаблоны и пропсы:

  • Синтаксис шаблонов — Сниппет объявляется блочным синтаксисом разметки
  • `$props`: входные данные компонента — Сниппет передаётся и принимается как обычный проп
  • События компонентов — Как и сниппеты, обработчики теперь передаются через пропсы

Итог

  • Сниппет - переиспользуемый кусок разметки: {#snippet name(args)} объявляет, {@render name(args)} вставляет
  • Сниппет принимает аргументы как функция, поэтому один блок рисует разные данные
  • Сниппет передаётся в дочерний компонент как обычный проп и читается через `$props`
  • Контент между открывающим и закрывающим тегами компонента доступен как сниппет children
  • Сниппеты заменяют слоты Svelte 4 и снимают их ограничения: переиспользование, передача как значения, условный вызов

Связанные уроки

  • sv-04-template-syntax — Сниппеты живут в разметке и используют блочный синтаксис, знакомый по шаблонам
  • sv-09-props — Сниппет передаётся в дочерний компонент как обычный проп через `$props`
  • sv-13-component-events — И сниппеты, и callback-пропсы передаются через пропсы, заменяя старые специальные механизмы
Snippets: замена слотам

0

1

Войти