Skip to content

Commit 11db0db

Browse files
authored
docs: Update watcher side effect cleanup + WatchHandle pause / resume (#2272)
* docs: Update watcher side effect cleanup + WatchHandle pause / resume * fix: Correct for accurate translation
1 parent 4706b8f commit 11db0db

File tree

2 files changed

+232
-4
lines changed

2 files changed

+232
-4
lines changed

src/api/reactivity-core.md

Lines changed: 110 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@
238238
function watchEffect(
239239
effect: (onCleanup: OnCleanup) => void,
240240
options?: WatchEffectOptions
241-
): StopHandle
241+
): WatchHandle
242242
243243
type OnCleanup = (cleanupFn: () => void) => void
244244
@@ -248,7 +248,12 @@
248248
onTrigger?: (event: DebuggerEvent) => void
249249
}
250250
251-
type StopHandle = () => void
251+
interface WatchHandle {
252+
(): void // 呼び出し可能、`stop` と同様
253+
pause: () => void
254+
resume: () => void
255+
stop: () => void
256+
}
252257
```
253258

254259
- **詳細**
@@ -295,6 +300,47 @@
295300
stop()
296301
```
297302

303+
ウォッチャーの一時停止 / 再開: <sup class="vt-badge" data-text="3.5+" />
304+
305+
```js
306+
const { stop, pause, resume } = watchEffect(() => {})
307+
308+
// ウォッチャーを一時停止する
309+
pause()
310+
311+
// あとで再開する
312+
resume()
313+
314+
// 停止する
315+
stop()
316+
```
317+
318+
副作用のクリーンアップ:
319+
320+
```js
321+
watchEffect(async (onCleanup) => {
322+
const { response, cancel } = doAsyncWork(newId)
323+
// `id` が変更されると `cancel` が呼ばれ、
324+
// 前のリクエストがまだ完了していない場合はキャンセルされます
325+
onCleanup(cancel)
326+
data.value = await response
327+
})
328+
```
329+
330+
3.5+ での副作用のクリーンアップ:
331+
332+
```js
333+
import { onWatcherCleanup } from 'vue'
334+
335+
watchEffect(async () => {
336+
const { response, cancel } = doAsyncWork(newId)
337+
// `id` が変更されると `cancel` が呼ばれ、
338+
// 前のリクエストがまだ完了していない場合はキャンセルされます
339+
onWatcherCleanup(cancel)
340+
data.value = await response
341+
})
342+
```
343+
298344
オプション:
299345

300346
```js
@@ -333,14 +379,14 @@
333379
source: WatchSource<T>,
334380
callback: WatchCallback<T>,
335381
options?: WatchOptions
336-
): StopHandle
382+
): WatchHandle
337383
338384
// 複数ソースの監視
339385
function watch<T>(
340386
sources: WatchSource<T>[],
341387
callback: WatchCallback<T[]>,
342388
options?: WatchOptions
343-
): StopHandle
389+
): WatchHandle
344390
345391
type WatchCallback<T> = (
346392
value: T,
@@ -363,6 +409,13 @@
363409
onTrigger?: (event: DebuggerEvent) => void
364410
once?: boolean // 初期値: false
365411
}
412+
413+
interface WatchHandle {
414+
(): void // 呼び出し可能、`stop` と同様
415+
pause: () => void
416+
resume: () => void
417+
stop: () => void
418+
}
366419
```
367420

368421
> 読みやすくするため、型は単純化されています。
@@ -472,6 +525,21 @@
472525
stop()
473526
```
474527

528+
ウォッチャーの一時停止 / 再開: <sup class="vt-badge" data-text="3.5+" />
529+
530+
```js
531+
const { stop, pause, resume } = watchEffect(() => {})
532+
533+
// ウォッチャーを一時停止する
534+
pause()
535+
536+
// あとで再開する
537+
resume()
538+
539+
// 停止する
540+
stop()
541+
```
542+
475543
副作用のクリーンアップ:
476544

477545
```js
@@ -484,7 +552,45 @@
484552
})
485553
```
486554

555+
3.5+ での副作用のクリーンアップ:
556+
557+
```js
558+
import { onWatcherCleanup } from 'vue'
559+
560+
watch(id, async (newId) => {
561+
const { response, cancel } = doAsyncWork(newId)
562+
onWatcherCleanup(cancel)
563+
data.value = await response
564+
})
565+
```
566+
487567
- **参照**
488568

489569
- [ガイド - ウォッチャー](/guide/essentials/watchers)
490570
- [ガイド - ウォッチャーのデバッグ](/guide/extras/reactivity-in-depth#watcher-debugging)
571+
572+
## onWatcherCleanup() <sup class="vt-badge" data-text="3.5+" /> {#onwatchercleanup}
573+
574+
現在のウォッチャーが再実行される直前に実行されるクリーンアップ関数を登録します。`watchEffect` エフェクト関数または `watch` コールバック関数の同期実行中にのみ呼び出すことができます(つまり、非同期関数内の `await` ステートメントの後には呼び出すことができません)。
575+
576+
- ****
577+
578+
```ts
579+
function onWatcherCleanup(
580+
cleanupFn: () => void,
581+
failSilently?: boolean
582+
): void
583+
```
584+
585+
- ****
586+
587+
```ts
588+
import { watch, onWatcherCleanup } from 'vue'
589+
590+
watch(id, (newId) => {
591+
const { response, cancel } = doAsyncWork(newId)
592+
// `id` が変更されると `cancel` が呼ばれ、
593+
// 前のリクエストがまだ完了していない場合はキャンセルされます
594+
onWatcherCleanup(cancel)
595+
})
596+
```

src/guide/essentials/watchers.md

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,128 @@ watchEffect(async () => {
362362

363363
</div>
364364

365+
## 副作用のクリーンアップ {#side-effect-cleanup}
366+
367+
ウォッチャー内で、例えば非同期リクエストなど、副作用が伴う場合があります:
368+
369+
<div class="composition-api">
370+
371+
```js
372+
watch(id, (newId) => {
373+
fetch(`/api/${newId}`).then(() => {
374+
// コールバックのロジック
375+
})
376+
})
377+
```
378+
379+
</div>
380+
<div class="options-api">
381+
382+
```js
383+
export default {
384+
watch: {
385+
id(newId) {
386+
fetch(`/api/${newId}`).then(() => {
387+
// コールバックのロジック
388+
})
389+
}
390+
}
391+
}
392+
```
393+
394+
</div>
395+
396+
しかし、リクエストが完了する前に `id` が変更されたらどうなるでしょう?前のリクエストが完了したときに、すでに古くなった ID 値でコールバックが発火してしまいます。理想的には、`id` が新しい値に変更されたときに古いリクエストをキャンセルしたいです。
397+
398+
[`onWatcherCleanup()`](/api/reactivity-core#onwatchercleanup) <sup class="vt-badge" data-text="3.5+" /> API を使って、ウォッチャーが無効になり再実行される直前に呼び出されるクリーンアップ関数を登録することができます:
399+
400+
<div class="composition-api">
401+
402+
```js {10-13}
403+
import { watch, onWatcherCleanup } from 'vue'
404+
405+
watch(id, (newId) => {
406+
const controller = new AbortController()
407+
408+
fetch(`/api/${newId}`, { signal: controller.signal }).then(() => {
409+
// コールバックのロジック
410+
})
411+
412+
onWatcherCleanup(() => {
413+
// 古くなったリクエストを中止する
414+
controller.abort()
415+
})
416+
})
417+
```
418+
419+
</div>
420+
<div class="options-api">
421+
422+
```js {12-15}
423+
import { onWatcherCleanup } from 'vue'
424+
425+
export default {
426+
watch: {
427+
id(newId) {
428+
const controller = new AbortController()
429+
430+
fetch(`/api/${newId}`, { signal: controller.signal }).then(() => {
431+
// コールバックのロジック
432+
})
433+
434+
onWatcherCleanup(() => {
435+
// 古くなったリクエストを中止する
436+
controller.abort()
437+
})
438+
}
439+
}
440+
}
441+
```
442+
443+
</div>
444+
445+
`onWatcherCleanup` は Vue 3.5+ でのみサポートされており、`watchEffect` エフェクト関数または `watch` コールバック関数の同期実行中に呼び出す必要があることに注意してください: 非同期関数の `await` ステートメントの後に呼び出すことはできません。
446+
447+
代わりに、`onCleanup` 関数も第 3 引数としてウォッチャーコールバックに渡され<span class="composition-api">、`watchEffect` エフェクト関数には第 1 引数として渡され</span>ます:
448+
449+
<div class="composition-api">
450+
451+
```js
452+
watch(id, (newId, oldId, onCleanup) => {
453+
// ...
454+
onCleanup(() => {
455+
// クリーンアップのロジック
456+
})
457+
})
458+
459+
watchEffect((onCleanup) => {
460+
// ...
461+
onCleanup(() => {
462+
// クリーンアップのロジック
463+
})
464+
})
465+
```
466+
467+
</div>
468+
<div class="options-api">
469+
470+
```js
471+
export default {
472+
watch: {
473+
id(newId, oldId, onCleanup) {
474+
// ...
475+
onCleanup(() => {
476+
// クリーンアップのロジック
477+
})
478+
}
479+
}
480+
}
481+
```
482+
483+
</div>
484+
485+
これは 3.5 以前のバージョンで動作します。また、関数の引数で渡される `onCleanup` はウォッチャーインスタンスにバインドされるため、`onWatcherCleanup` の同期的な制約は受けません。
486+
365487
## コールバックが実行されるタイミング {#callback-flush-timing}
366488

367489
リアクティブな状態が変更されるとき、Vue コンポーネントの更新と生成されたウォッチャーコールバックを実行します。

0 commit comments

Comments
 (0)