$props
Входные данные компонента называются props, что является сокращением от properties. Вы передаете пропсы компонентам так же, как передаете атрибуты элементам:
<script> import MyComponent from './MyComponent.svelte';</script>
<MyComponent adjective="cool" />
<script lang="ts"> import MyComponent from './MyComponent.svelte';</script>
<MyComponent adjective="cool" />
С другой стороны, внутри MyComponent.svelte
мы можем получать пропсы с помощью руны $props
…
<script> let props = $props();</script>
<p>этот компонент — {props.adjective}</p>
<script lang="ts"> let props = $props();</script>
<p>этот компонент — {props.adjective}</p>
…хотя чаще всего вы будете деструктурировать ваши пропсы:
<script> let { adjective } = $props();</script>
<p>этот компонент — {adjective}</p>
<script lang="ts"> let { adjective } = $props();</script>
<p>этот компонент — {adjective}</p>
Значения по умолчанию
Заголовок раздела «Значения по умолчанию»Деструктуризация позволяет нам объявлять значения по умолчанию, которые используются, если родительский компонент не устанавливает данный проп (или значение undefined
):
let { adjective = 'happy' } = $props();
Переименование пропсов
Заголовок раздела «Переименование пропсов»Мы также можем использовать деструктурирующее присваивание для переименования пропсов, что необходимо, если они являются недопустимыми идентификаторами или ключевым словом JavaScript, таким как super
:
let { super: trouper = 'свет меня найдёт' } = $props();
Остаточные пропсы
Заголовок раздела «Остаточные пропсы»Наконец, мы можем использовать остаточное свойство (rest property), чтобы получить все остальные, необъявленные, пропсы:
let { a, b, c, ...others } = $props();
Обновление пропсов
Заголовок раздела «Обновление пропсов»Ссылки на проп внутри компонента обновляются, когда сам проп обновляется — когда count
изменяется в App.svelte
, он также изменится внутри Child.svelte
. Однако дочерний компонент может временно переопределить значение пропа, что может быть полезно для несохранённого эфемерного состояния (демонстрация):
<script> import Child from './Child.svelte';
let count = $state(0);</script>
<button onclick={() => (count += 1)}> нажатий (parent): {count}</button>
<Child {count} />
<script lang="ts"> import Child from './Child.svelte';
let count = $state(0);</script>
<button onclick={() => (count += 1)}> нажатий (parent): {count}</button>
<Child {count} />
<script> let { count } = $props();</script>
<button onclick={() => (count += 1)}> нажатий (child): {count}</button>
<script lang="ts"> let { count } = $props();</script>
<button onclick={() => (count += 1)}> нажатий (child): {count}</button>
Хотя вы можете временно переопределять пропсы, вы не должны их изменять, если они не являются привязываемыми.
Если проп является обычным объектом, изменение не окажет никакого эффекта (демонстрация):
<script> import Child from './Child.svelte';</script>
<Child object={{ count: 0 }} />
<script lang="ts"> import Child from './Child.svelte';</script>
<Child object={{ count: 0 }} />
<script> let { object } = $props();</script>
<button onclick={() => { // не имеет эффекта object.count += 1}}> нажатий: {object.count}</button>
<script lang="ts"> let { object } = $props();</script>
<button onclick={() => { // не имеет эффекта object.count += 1}}> нажатий: {object.count}</button>
Однако, если проп является прокси реактивного состояния, то изменения будут иметь эффект, но вы увидите предупреждение ownership_invalid_mutation
, потому что компонент изменяет состояние, которое ему не «принадлежит» (демонстрация):
<script> import Child from './Child.svelte';
let object = $state({count: 0});</script>
<Child {object} />
<script lang="ts"> import Child from './Child.svelte';
let object = $state({count: 0});</script>
<Child {object} />
<script> let { object } = $props();</script>
<button onclick={() => { // вызовет обновление счётчика ниже, // но с предупреждением. Не изменяйте // объекты, которые вам не принадлежат! object.count += 1}}> нажатий: {object.count}</button>
<script lang="ts"> let { object } = $props();</script>
<button onclick={() => { // вызовет обновление счётчика ниже, // но с предупреждением. Не изменяйте // объекты, которые вам не принадлежат! object.count += 1}}> нажатий: {object.count}</button>
Стандартное значение пропа, не объявленного с помощью $bindable
, остается нетронутым — оно не превращается в прокси реактивного состояния — что означает, что изменения не вызовут обновления (демонстрация)
<script> let { object = { count: 0 } } = $props();</script>
<button onclick={() => { // не имеет эффекта, если используется значение по умолчанию object.count += 1}}> нажатий: {object.count}</button>
<script lang="ts"> 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()
Заголовок раздела «$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>