Skip to content

Commit d17ade9

Browse files
authored
3.5: reactive props destructure (#2277)
* 3.5: reactive props destructure * docs: fix quotation marks in code comments * docs: fix to bring it closer to the nuances of the original text
1 parent 7b17d33 commit d17ade9

File tree

3 files changed

+92
-7
lines changed

3 files changed

+92
-7
lines changed

src/api/sfc-script-setup.md

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -209,12 +209,48 @@ const emit = defineEmits<{
209209

210210
この制限は 3.3 で解決されました。Vue の最新バージョンは型引数の位置でインポートされた複雑な型の限定されたセットを参照することをサポートしています。しかし、型からランタイムへの変換は依然として AST ベースであるため、実際の型解析を必要とするいくつかの複雑な型、例えば条件型など、はサポートされていません。条件型は単一の props の型には使用できますが、props オブジェクト全体の型には使用できません。
211211

212-
### 型宣言を使用時のデフォルトの props 値 {#default-props-values-when-using-type-declaration}
212+
### リアクティブな props の分割代入 <sup class="vt-badge" data-text="3.5+" /> {#reactive-props-destructure}
213213

214-
型のみの `defineProps` 宣言の欠点は、props のデフォルト値を提供する方法がないことです。この問題を解決するために、`withDefaults` コンパイラーマクロも用意されています:
214+
Vue 3.5 以降、`defineProps` の戻り値から分割代入された変数はリアクティブです。同じ `<script setup>` ブロック内で `defineProps` から分割代入された変数にアクセスするコードがあると、Vue のコンパイラーは自動的に `props.` を先頭に追加します:
215215

216216
```ts
217-
export interface Props {
217+
const { foo } = defineProps(['foo'])
218+
219+
watchEffect(() => {
220+
// 3.5 以前は 1 回だけ実行されます。
221+
// 3.5 以降は "foo" が変更されるたびに再実行されます。
222+
console.log(foo)
223+
})
224+
```
225+
226+
上記のコードがコンパイルされると以下のようになります:
227+
228+
```js {5}
229+
const props = defineProps(['foo'])
230+
231+
watchEffect(() => {
232+
// `foo` はコンパイラーによって `props.foo` に変換されました。
233+
console.log(props.foo)
234+
})
235+
```
236+
237+
さらに、JavaScript のネイティブなデフォルト値構文を使用して、props のデフォルト値を宣言できます。これは型ベースの props 宣言を使用する場合に特に便利です:
238+
239+
```ts
240+
interface Props {
241+
msg?: string
242+
labels?: string[]
243+
}
244+
245+
const { msg = 'hello', labels = ['one', 'two'] } = defineProps<Props>()
246+
```
247+
248+
### 型宣言を使用時のデフォルトの props 値 <sup class="vt-badge ts" /> {#default-props-values-when-using-type-declaration}
249+
250+
3.5 以降では、リアクティブな props の分割代入を使用すると、自然な形でデフォルト値を宣言できます。しかし、3.4 以前では、リアクティブな props の分割代入はデフォルトで有効になっていません。型ベースの宣言で props のデフォルト値を宣言するには、`withDefaults` コンパイラーマクロが必要です:
251+
252+
```ts
253+
interface Props {
218254
msg?: string
219255
labels?: string[]
220256
}
@@ -228,7 +264,7 @@ const props = withDefaults(defineProps<Props>(), {
228264
これは、同等なランタイム props の `default` オプションにコンパイルされます。さらに、`withDefaults` ヘルパーは、デフォルト値の型チェックを行います。また、返される `props` の型が、デフォルト値が宣言されているプロパティに対して、省略可能フラグが削除されていることを保証します。
229265

230266
:::info
231-
変更可能な参照型(配列やオブジェクトなど)のデフォルト値は、偶発的な変更や外部からの副作用を避けるために、関数でラップする必要があることに注意してください。こうすることで、各コンポーネントのインスタンスがデフォルト値のコピーを取得することが保証されます。
267+
変更可能な参照型(配列やオブジェクトなど)のデフォルト値は、偶発的な変更や外部からの副作用を避けるために `withDefaults` を使う時は、関数でラップする必要があることに注意してください。こうすることで、各コンポーネントのインスタンスがデフォルト値のコピーを取得することが保証されます。これは分割代入でデフォルト値を使う時は**不要**です
232268
:::
233269

234270
## defineModel() <sup class="vt-badge" data-text="3.4+" /> {#definemodel}
@@ -487,7 +523,6 @@ ref<InstanceType<typeof componentWithoutGenerics>>();
487523
ref<ComponentExposed<typeof genericComponent>>();
488524
```
489525

490-
491526
## 制限 {#restrictions}
492527

493528
- モジュールの実行セマンティクスの違いにより、`<script setup>` 内のコードは、SFC のコンテキストに依存しています。外部の `.js``.ts` ファイルに移動すると、開発者とツールの両方に混乱を招く可能性があります。そのため、**`<script setup>`** は、`src` 属性と一緒に使うことはできません。

src/guide/components/props.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,45 @@ defineProps<{
117117

118118
</div>
119119

120+
<div class="composition-api">
121+
122+
## リアクティブな props の分割代入 <sup class="vt-badge" data-text="3.5+" /> \*\* {#reactive-props-destructure}
123+
124+
Vue のリアクティビティシステムは、プロパティアクセスに基づいて状態の使用を追跡します。例えば、算出プロパティやウォッチャーで `props.foo` にアクセスすると、`foo` プロパティが依存関係として追跡されます。
125+
126+
そこで、以下のようなコードを考えます:
127+
128+
```js
129+
const { foo } = defineProps(['foo'])
130+
131+
watchEffect(() => {
132+
// 3.5 以前は 1 回だけ実行されます。
133+
// 3.5 以降は "foo" が変更されるたびに再実行されます。
134+
console.log(foo)
135+
})
136+
```
137+
138+
バージョン 3.4 以前では、`foo` は実際の定数であり、変更されることはありません。バージョン 3.5 以降では、同じ `<script setup>` ブロック内で `defineProps` から分割代入された変数にアクセスするコードがあると、Vue のコンパイラーは自動的に `props.` を先頭に追加します。したがって、上記のコードは以下のようになります:
139+
140+
```js {5}
141+
const props = defineProps(['foo'])
142+
143+
watchEffect(() => {
144+
// `foo` はコンパイラーによって `props.foo` に変換されました。
145+
console.log(props.foo)
146+
})
147+
```
148+
149+
さらに、JavaScript のネイティブなデフォルト値構文を使用して、props のデフォルト値を宣言できます。これは型ベースの props 宣言を使用する場合に特に便利です:
150+
151+
```ts
152+
const { foo = 'hello' } = defineProps<{ foo?: string }>()
153+
```
154+
155+
### 関数への分割代入 props 渡し
156+
157+
</div>
158+
120159
## props 渡しの詳細 {#prop-passing-details}
121160

122161
### props 名の大文字・小文字の使い分け {#prop-name-casing}

src/guide/typescript/composition-api.md

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,18 @@ const props = defineProps<Props>()
6868

6969
### props のデフォルト値 {#props-default-values}
7070

71-
型ベースの宣言を使用すると、props のデフォルト値を宣言できません。これは、`withDefaults` コンパイラーマクロによって解決できます:
71+
型ベースの宣言を使用すると、props のデフォルト値を宣言できません。これは、[リアクティブな props の分割代入](/guide/components/props#reactive-props-destructure) <sup class="vt-badge" data-text="3.5+" /> によって解決できます:
72+
73+
```ts
74+
export interface Props {
75+
msg?: string
76+
labels?: string[]
77+
}
78+
79+
const { msg = 'hello', labels = ['one', 'two'] } = defineProps<Props>()
80+
```
81+
82+
3.4 以下ではリアクティブな props の分割代入はデフォルトでは有効ではありません。代わりに `withDefaults` コンパイラーマクロを使用します:
7283

7384
```ts
7485
export interface Props {
@@ -85,7 +96,7 @@ const props = withDefaults(defineProps<Props>(), {
8596
これは、ランタイム props の `default` オプションと同等にコンパイルされます。さらに、`withDefaults` ヘルパーはデフォルト値の型チェックを提供し、戻り値の `props` の型からはデフォルト値が宣言されているプロパティのオプションフラグが削除されていることを保証します。
8697

8798
:::info
88-
変更可能な参照型(配列やオブジェクトなど)のデフォルト値は、偶発的な変更や外部からの副作用を避けるために、関数でラップする必要があることに注意してください。こうすることで、各コンポーネントのインスタンスがデフォルト値のコピーを取得することが保証されます。
99+
変更可能な参照型(配列やオブジェクトなど)のデフォルト値は、偶発的な変更や外部からの副作用を避けるために `withDefaults` を使う時は、関数でラップする必要があることに注意してください。こうすることで、各コンポーネントのインスタンスがデフォルト値のコピーを取得することが保証されます。これは分割代入でデフォルト値を使う時は**不要**です
89100
:::
90101

91102
### `<script setup>` を使用しない場合 {#without-script-setup}

0 commit comments

Comments
 (0)