$props
コンポーネントへの入力は props (プロパティの省略形) と呼ばれます。属性を要素に渡すのと同じように、props をコンポーネントに渡します:
<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
rune を使用して props を受け取ることができます...
<script>
let props = $props();
</script>
<p>this component is {props.adjective}</p>
<script lang="ts">
let props = $props();
</script>
<p>this component is {props.adjective}</p>
...ただし、一般的には props を 分割代入 することが多いです:
<script>
let { adjective } = $props();
</script>
<p>this component is {adjective}</p>
<script lang="ts">
let { adjective } = $props();
</script>
<p>this component is {adjective}</p>
Fallback values
分割代入を使用するとフォールバック値を宣言できます。これは親コンポーネントが特定の props を設定しない場合に使用されます:
let { let adjective: any
adjective = 'happy' } = function $props(): any
Declares the props that a component accepts. Example:
let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props();
$props();
フォールバック値はリアクティブな state proxy には変換されません (Updating props を参照してください)
Renaming props
分割代入を使用して props をリネームすることもできます。これは元の props の名前が無効な識別子や super
のような JavaScript キーワードである場合に必要となります:
let { super: let trouper: any
trouper = 'lights are gonna find me' } = function $props(): any
Declares the props that a component accepts. Example:
let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props();
$props();
Rest props
最後に、rest property を使用して、他のすべての props を取得できます:
let { let a: any
a, let b: any
b, let c: any
c, ...let others: any
others } = function $props(): any
Declares the props that a component accepts. Example:
let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props();
$props();
Updating props
コンポーネント内の props に対する参照は、その props 自体が更新されると更新されます — App.svelte
の count
が変更されると、それは Child.svelte
内でも変更されます。ただし、子コンポーネントは一時的に prop の値を上書きすることができ、これは保存されない一時的な state として便利です (demo):
<script>
import Child from './Child.svelte';
let count = $state(0);
</script>
<button onclick={() => (count += 1)}>
clicks (parent): {count}
</button>
<Child {count} />
<script lang="ts">
import Child from './Child.svelte';
let count = $state(0);
</script>
<button onclick={() => (count += 1)}>
clicks (parent): {count}
</button>
<Child {count} />
<script>
let { count } = $props();
</script>
<button onclick={() => (count += 1)}>
clicks (child): {count}
</button>
<script lang="ts">
let { count } = $props();
</script>
<button onclick={() => (count += 1)}>
clicks (child): {count}
</button>
props は一時的に再代入(reassign)することができます。一方で、bindable でない限り変異(mutate)すべきではありません。
prop が通常のオブジェクトの場合、変異させても何の効果もありません (デモ):
<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={() => {
// has no effect
object.count += 1
}}>
clicks: {object.count}
</button>
<script lang="ts">
let { object } = $props();
</script>
<button onclick={() => {
// has no effect
object.count += 1
}}>
clicks: {object.count}
</button>
props がリアクティブな state proxy の場合、変異(mutation)は反映されますが、ownership_invalid_mutation
警告が表示されます。これは、そのコンポーネントが「所有していない」state を変異(mutate)しているためです (デモ):
<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={() => {
// will cause the count below to update,
// but with a warning. Don't mutate
// objects you don't own!
object.count += 1
}}>
clicks: {object.count}
</button>
<script lang="ts">
let { object } = $props();
</script>
<button onclick={() => {
// will cause the count below to update,
// but with a warning. Don't mutate
// objects you don't own!
object.count += 1
}}>
clicks: {object.count}
</button>
$bindable
として宣言されていない props のフォールバック値はそのままです — リアクティブな state proxy には変換されません — つまり変異(mutation)しても更新は発生しません (デモ)
<script>
let { object = { count: 0 } } = $props();
</script>
<button onclick={() => {
// has no effect if the fallback value is used
object.count += 1
}}>
clicks: {object.count}
</button>
<script lang="ts">
let { object = { count: 0 } } = $props();
</script>
<button onclick={() => {
// has no effect if the fallback value is used
object.count += 1
}}>
clicks: {object.count}
</button>
要約: props を変異(mutate)しないでください。変更を伝えるためにコールバック props を使用するか、親と子が同じオブジェクトを共有する必要がある場合は $bindable
rune を使用してください。
Type safety
他の変数宣言と同様に、props にアノテーションを付けることでコンポーネントに型安全性を追加できます。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>
ネイティブ DOM 要素用のインターフェースは
svelte/elements
モジュールで提供されています (Typing wrapper components を参照してください)
型を追加することをお勧めします。これにより、コンポーネントを使用する人々が、渡すべき props を簡単に発見できるようになります。