Перейти к содержимому
GitHub

$props

Входные данные компонента называются props, что является сокращением от properties. Вы передаете пропсы компонентам так же, как передаете атрибуты элементам:

// App.svelte
<script>
  import MyComponent from './MyComponent.svelte';
</script>

<MyComponent adjective="cool" />

С другой стороны, внутри MyComponent.svelte мы можем получать пропсы с помощью руны $props

// MyComponent.svelte
<script>
  let props = $props();
</script>

<p>этот компонент — {props.adjective}</p>

…хотя чаще всего вы будете деструктурировать ваши пропсы:

// MyComponent.svelte
<script>
  let { adjective } = $props();
</script>

<p>этот компонент — {adjective}</p>

Значения по умолчанию

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

let { adjective = 'happy' } = $props();

Переименование пропсов

Мы также можем использовать деструктурирующее присваивание для переименования пропсов, что необходимо, если они являются недопустимыми идентификаторами или ключевым словом JavaScript, таким как super:

let { super: trouper = 'свет меня найдёт' } = $props();

Остаточные пропсы

Наконец, мы можем использовать остаточное свойство (rest property), чтобы получить все остальные, необъявленные, пропсы:

let { a, b, c, ...others } = $props();

Обновление пропсов

Ссылки на пропс внутри компонента обновляются, когда сам пропс обновляется — когда count изменяется в App.svelte, он также изменится внутри Child.svelte. Однако дочерний компонент может временно переопределить значение пропса, что может быть полезно для несохранённого эфемерного состояния (демонстрация):

// App.svelte
<script>
  import Child from './Child.svelte';

  let count = $state(0);
</script>

<button onclick={() => (count += 1)}>
  нажатий (parent): {count}
</button>

<Child {count} />
// Child.svelte
<script>
  let { count } = $props();
</script>

<button onclick={() => (count += 1)}>
  нажатий (child): {count}
</button>

Хотя вы можете временно переопределять пропсы, вы не должны их изменять, если они не являются привязываемыми.

Если пропс является обычным объектом, изменение не окажет никакого эффекта (демонстрация):

// App.svelte
<script>
  import Child from './Child.svelte';
</script>

<Child object={{ count: 0 }} />
// Child.svelte
<script>
  let { object } = $props();
</script>

<button onclick={() => {
  // не имеет эффекта
  object.count += 1
}}>
  нажатий: {object.count}
</button>

Однако, если пропс является прокси реактивного состояния, то изменения будут иметь эффект, но вы увидите предупреждение ownership_invalid_mutation, потому что компонент изменяет состояние, которое ему не «принадлежит» (демонстрация):

// App.svelte
<script>
  import Child from './Child.svelte';

  let object = $state({count: 0});
</script>

<Child {object} />
// Child.svelte
<script>
  let { object } = $props();
</script>

<button onclick={() => {
  // вызовет обновление счётчика ниже,
  // но с предупреждением. Не изменяйте
  // объекты, которые вам не принадлежат!
  object.count += 1
}}>
  нажатий: {object.count}
</button>

Значение по умолчанию пропса, не объявленного с помощью $bindable, остается нетронутым — оно не превращается в прокси реактивного состояния — что означает, что изменения не вызовут обновления (демонстрация)

// Child.svelte
<script>
  let { object = { count: 0 } } = $props();
</script>

<button onclick={() => {
  // не имеет эффекта, если используется значение по умолчанию
  object.count += 1
}}>
  нажатий: {object.count}
</button>

В заключение: не изменяйте пропсы. Либо используйте колбэк-пропсы для передачи изменений, либо — если родитель и потомок должны использовать один и тот же объект — используйте руну $bindable.

Безопасность типов

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

<script lang="ts">
  let { adjective }: { adjective: string } = $props();
</script>

…в то время как в JSDoc вы можете сделать это так:

<script>
  /** @type {{ adjective: string }} */
  let { adjective } = $props();
</script>

Вы, конечно, можете отделить объявление типа от аннотации:

<script lang="ts">
  interface Props {
    adjective: string;
  }

  let { adjective }: Props = $props();
</script>

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

$props.id()

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

Это особенно удобно для связывания элементов с помощью атрибутов, таких как for и aria-labelledby.

<script>
  const uid = $props.id();
</script>

<form>
  <label for="{uid}-firstname">First Name: </label>
  <input id="{uid}-firstname" type="text" />

  <label for="{uid}-lastname">Last Name: </label>
  <input id="{uid}-lastname" type="text" />
</form>