Пропсы и руна $props

Руна $props объявляет входные данные компонента — как параметры функции, но для UI.

«Компонент без пропсов — это монолог. Пропсы превращают его в диалог с родителем.»

Компоненты становятся по-настоящему полезными, когда их можно переиспользовать с разными данными. Карточка пользователя должна показывать любого пользователя, кнопка — любой текст. Данные, которые родитель передаёт ребёнку, называются пропсами (свойствами). В Svelte 5 компонент объявляет свои пропсы руной $props.

Синтаксис элегантен: вы деструктурируете пропсы прямо из вызова $props(). Это сразу видно как контракт компонента — что он принимает снаружи. Можно задавать значения по умолчанию и переименовывать.

<!-- UserCard.svelte -->
<script>
  let { name, age = 18, role = 'студент' } = $props();
</script>

<article>
  <h3>{name}</h3>
  <p>{age} лет, {role}</p>
</article>

Родитель использует компонент как HTML-тег, передавая пропсы атрибутами:

<!-- родитель -->
<script>
  import UserCard from './UserCard.svelte';
</script>

<UserCard name="Аня" age={17} />
<UserCard name="Борис" role="наставник" />

Заметьте: строку можно передать в кавычках, а число или выражение — в фигурных скобках. Пропс age у Бориса не передан, поэтому подставится значение по умолчанию — 18. Пропсы в Svelte однонаправлены: данные текут сверху вниз, от родителя к ребёнку. Это делает поток предсказуемым.

Как это работает под капотом

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

// Компонент как функция, принимающая пропсы
function UserCard(props) {
  const { name, age = 18, role = 'студент' } = props; // дефолты
  return `<article><h3>${name}</h3><p>${age} лет, ${role}</p></article>`;
}

console.log(UserCard({ name: 'Аня', age: 17 }));
console.log(UserCard({ name: 'Борис', role: 'наставник' })); // age по умолчанию

Попробуй сам ▶ — вставь код в консоль браузера (F12 → Console) и нажми Enter, чтобы увидеть вывод.

В реальном Svelte пропсы ещё и реактивны: если родитель передаёт реактивное значение, обновление прилетит вниз автоматически. Но базовая ментальная модель — «пропсы это параметры» — верна.

  Родитель
    |
    |  name="Аня" age={17}
    v
  $props()  ->  { name, age, role }
    |
    v
  разметка UserCard использует значения

Частые ошибки

  • Пытаться записывать в пропс напрямую. Пропсы текут сверху вниз; для двусторонней связи есть $bindable.
  • Путать строку и выражение. age="17" передаст строку, а age={17} — число.
  • Забывать значения по умолчанию, из-за чего компонент падает на отсутствующих пропсах.

Best practices

  • Задавайте разумные значения по умолчанию — это делает компонент устойчивым.
  • С TypeScript типизируйте пропсы: let { name }: { name: string } = $props().
  • Держите список пропсов небольшим; если их много, возможно, компонент делает слишком многое.

Проектирование удобного интерфейса компонента

Список пропсов — это публичный контракт компонента, по сути его API. Хорошо спроектированный набор пропсов делает компонент приятным в использовании, плохой — превращает каждое применение в борьбу. Несколько ориентиров из практики. Давайте пропсам говорящие имена, отражающие смысл, а не реализацию. Снабжайте необязательные пропсы разумными значениями по умолчанию, чтобы в простом случае компонент работал без лишней настройки. Не раздувайте список: если у компонента десяток пропсов, это сигнал, что он, возможно, делает слишком много и его стоит разбить. С TypeScript обязательно типизируйте пропсы — тип служит и документацией, и страховкой от опечаток. Помните, что пропсы однонаправлены: компонент получает данные сверху и не должен пытаться их перезаписывать. Если ребёнку нужно сообщить родителю об изменении, для этого есть колбэки, о которых мы поговорим в следующем уроке.

Итог: $props объявляет входные данные компонента через деструктуризацию, поддерживает значения по умолчанию и реализует однонаправленный поток данных сверху вниз.

Проверьте себя
1. Как компонент в Svelte 5 объявляет принимаемые пропсы?
Aexport let name
Blet { name, age = 18 } = $props()
Cprops.name
Dthis.props = { name }
2. В каком направлении по умолчанию текут пропсы?
AОт ребёнка к родителю
BВ обе стороны автоматически
CСверху вниз: от родителя к ребёнку
DТолько горизонтально между соседями