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

$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>

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

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>

Если ваш компонент использует пропсы в виде сниппетов (в том числе children), типизируйте их через интерфейс Snippet из модуля 'svelte'.

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

Эта руна, появившаяся в версии 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>