Svelte

`$props` и `$bindable`

Компонент Avatar показывает картинку и имя, и в разных местах ему передают разные данные: где-то только имя, где-то имя с размером, где-то ещё и обработчик клика. Компоненту нужен способ объявить, какие входные данные он принимает. В Svelte 5 это руна `$props`: одна строка деструктуризации описывает все входы, задаёт значения по умолчанию и собирает остальное. А когда родителю и потомку нужно делить одно значение в обе стороны - например, поле формы - подключается `$bindable`.

  • Кнопка с props label, variant и disabled - один компонент под десятки мест применения
  • Поля ввода с двусторонней привязкой через `$bindable`: значение живёт в родителе, а правит его потомок
  • Карточки и списки получают данные элемента через props и значения по умолчанию для необязательных полей
  • Обёртки над HTML-элементами пробрасывают все лишние атрибуты через rest props на корневой тег
  • Дизайн-системы строят гибкие компоненты, комбинируя именованные props, дефолты и rest

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

  • Структура .svelte компонента и его использование как тега
  • JavaScript: деструктуризация объектов, значения по умолчанию, rest-оператор
  • Понятие реактивного состояния `$state` на уровне идеи

Приём props и значения по умолчанию

Руна `$props` возвращает объект со всеми входными данными, которые родитель передал компоненту. Чаще всего его сразу деструктурируют в отдельные переменные. В той же деструктуризации задают значения по умолчанию: если родитель не передал prop, берётся дефолт. Это заменяет старый синтаксис export let из Svelte 4.

Первый Avatar получает только name, поэтому size берётся по умолчанию равным 48, а src - дефолтной картинкой. Второй задаёт size равным 96. Запись с фигурными скобками src в разметке - это сокращение: атрибут src со значением переменной src. Props реактивны: если родитель передаёт реактивное значение и оно меняется, компонент перерисуется.

В Svelte 4 каждый prop объявлялся отдельной строкой export let. В Svelte 5 все входы описывает одна деструктуризация из `$props`, и значения по умолчанию пишутся там же привычным синтаксисом JavaScript. Меньше шаблонного кода и понятнее, какие props принимает компонент.

Что вернёт `$props()` и как обычно задают значение по умолчанию для prop?

Rest props и проброс атрибутов

Иногда компонент-обёртка должен принять несколько своих props и пробросить все остальные на внутренний элемент. Для этого в деструктуризации используют rest-оператор: именованные props забираются в переменные, а всё прочее собирается в один объект. Этот объект затем раскладывают на элемент через spread-атрибут.

Компонент Button забирает variant и children, а onclick и disabled попадают в объект rest и через spread оказываются на внутреннем теге button. Так обёртка остаётся гибкой: она не обязана перечислять каждый возможный HTML-атрибут. Запись render children - это вывод вложенной разметки, переданной между тегами компонента, через сниппет.

ЗаписьСмысл
let { a, b } = $props()Забрать именованные props a и b
let { a, ...rest } = $props()Забрать a, остальное собрать в rest
{...rest} на элементеРазложить собранные props как атрибуты
{@render children()}Вывести вложенную разметку (сниппет)

Специальный prop children содержит вложенную разметку, которую родитель положил между открывающим и закрывающим тегами компонента. Это замена слотам из Svelte 4. Вложенный контент - это сниппет, и выводится он командой `{@render children()}`.

Зачем компоненту-обёртке использовать rest props, как в `let { variant, ...rest } = $props()`?

`$bindable` для двусторонней привязки

По умолчанию поток данных односторонний: prop идёт от родителя к потомку, и потомок не меняет значение у родителя. Но иногда нужна двусторонняя связь - классический случай это компонент поля ввода, где значение должно жить у родителя, а правится внутри потомка. Для этого prop объявляют через руну `$bindable`. Тогда родитель может связать его директивой bind, и изменение в любую сторону отразится у обоих.

Внутри TextField prop value помечен как `$bindable` со значением по умолчанию. Родитель связывает его через bind:value с собственным состоянием email. Теперь ввод в поле меняет email у родителя, а если родитель поменяет email программно, обновится и поле. Без `$bindable` связать prop директивой bind нельзя - это защита от случайной мутации входных данных.

  • Обычный prop — Односторонний поток: значение идёт от родителя к потомку. Потомок читает его, но не меняет у родителя. Поведение предсказуемо и по умолчанию безопасно
  • Prop через `$bindable` — Двусторонний поток: родитель связывает его через bind, и изменение значения в потомке отражается у родителя. Применять только когда двусторонняя связь действительно нужна

`$bindable` стоит использовать осмотрительно. Двусторонняя привязка размывает направление потока данных и усложняет отслеживание, откуда пришло изменение. Для большинства props достаточно одностороннего потока: потомок сообщает наверх через колбэк-prop, а не меняет значение родителя напрямую.

Зачем prop объявляют через `$bindable`, как в `let { value = $bindable('') } = $props()`?

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

Props соединяют компоненты в дерево и завершают модуль реактивности:

  • Компонент .svelte — Props - входные данные компонента, который используется как тег
  • `$state`: реактивное состояние — `$bindable` связывает prop потомка с состоянием родителя в обе стороны
  • Руны: явная реактивность — `$props` и `$bindable` входят в пятёрку основных рун

Итог

  • Руна `$props` возвращает объект входных данных компонента, который обычно сразу деструктурируют в переменные
  • Значения по умолчанию задаются прямо в деструктуризации и применяются, когда prop не передан
  • Rest-оператор собирает все непоименованные props в один объект, удобно для проброса лишних атрибутов
  • По умолчанию поток данных односторонний: prop идёт от родителя к потомку, потомок его не меняет у родителя
  • Руна `$bindable` помечает prop как доступный для двусторонней привязки, и тогда родитель связывает его через bind

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

  • sv-03-components — Props - это способ передать данные в компонент, поэтому сначала нужен сам компонент
  • sv-06-state — `$bindable` связывает prop потомка с состоянием `$state` родителя в обе стороны
  • sv-05-runes-intro — `$props` и `$bindable` - две из пяти основных рун из вводного урока
`$props` и `$bindable`

0

1

Войти