Svelte_孫コンポーネントでの入力内容を親コンポーネントに伝える

props を使うと親コンポーネントと子コンポーネント間で値を割と利できることはわかっているが、孫コンポーネントまで値をやり取りする方法について考えた。

構成

以下のコンポーネント構成を考える。

1
2
3
4
+- 親コンポーネント(App.svelte)
+- 子コンポーネント(AppForm.svelte)
+- 孫コンポーネント(AppInput.svelte)
+- 孫コンポーネント(AppInput.svelte)

親コンポーネント( src/App.svelte )

1
2
3
4
5
6
7
8
9
10
<script lang="ts">
let message: string = 'Hello, world'
import AppForm from './AppForm.svelte';
import AppLabel from './AppLabel.svelte';
</script>

<h1>{message}</h1>

<AppLabel>Name</AppLabel>
<AppForm bind:value={message}></AppForm>

子コンポーネント( src/AppForm.svelte )

1
2
3
4
5
6
<script lang="ts">
import AppInput from './AppInput.svelte';
export let value: string = '';
</script>

<AppInput bind:value></AppInput>

孫コンポーネント( src/AppLabel.svelte )

1
2
3
4
<script>
</script>

<label><slot></slot></label>

孫コンポーネント( src/AppInput.svelte )

1
2
3
4
5
<script lang="ts">
export let value: string = '';
</script>

<input bind:value>

拡張バージョン

<input> タグにフォームの内容を上位コンポーネントから伝えるように拡張してみる。

src/App.svelte

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<script lang="ts">
let first_name: string = 'John'
let last_name: string = 'Smith'
import AppForm from './AppForm.svelte';
</script>

<h1>{first_name} {last_name}</h1>

<AppForm
bind:value={first_name}
name="first_name"
type="text"
title="First Name"
/>
<AppForm
bind:value={last_name}
name="last_name"
type="test"
title="Last Name"
/>

src/AppForm.svelte

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<script lang="ts">
import AppInput from './AppInput.svelte';
import AppLabel from './AppLabel.svelte';
export let name: string = '';
export let type: string = '';
export let value: string = '';
export let title: string = '';
</script>

<AppLabel
name={name}
title={title}
/>
<AppInput
type={type}
name={name}
bind:value
/>

src/AppLabel.svelte

1
2
3
4
5
6
<script lang="ts">
export let name:string = '';
export let title:string = '';
</script>

<label for={name}>{title}</label>

src/AppInput.svelte

1
2
3
4
5
6
7
8
9
10
11
<script lang="ts">
export let value: string = '';
export let type: string = '';
export let name: string;
const props = {
type,
name,
}
</script>

<input {...props} bind:value/>