Skip to content

Commit

Permalink
Merge pull request #111 from GuoXiCheng/dev-c
Browse files Browse the repository at this point in the history
update docs
  • Loading branch information
GuoXiCheng authored Oct 10, 2024
2 parents 07f94d4 + 25f82d2 commit 694da62
Show file tree
Hide file tree
Showing 4 changed files with 209 additions and 19 deletions.
39 changes: 31 additions & 8 deletions src/.vitepress/sidebars/vue.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,31 @@
items:
- text: 基本示例
link: /frontend/vue/watch/basic#基本示例
- text: 侦听源数据类型
link: /frontend/vue/watch/basic#侦听源数据类型
- text: 回调的触发时机
link: /frontend/vue/watch/basic#回调的触发时机
items:
- text: ref 或 reactive
link: /frontend/vue/watch/basic#ref-或-reactive
- text: getter 函数
link: /frontend/vue/watch/basic#getter-函数
- text: 多个侦听源
link: /frontend/vue/watch/basic#多个侦听源
- text: Vue 更新之前触发
link: /frontend/vue/watch/basic#vue-更新之前触发
- text: Vue 更新之后触发
link: /frontend/vue/watch/basic#vue-更新之后触发
- text: 副作用清理
link: /frontend/vue/watch/basic#副作用清理
items:
- text: onCleanup
link: /frontend/vue/watch/basic#oncleanup
- text: onWatcherCleanup
link: /frontend/vue/watch/basic#onwatchercleanup
- text: 停止侦听
link: /frontend/vue/watch/basic#停止侦听
- text: 侦听源数据类型
link: /frontend/vue/watch/source-type
items:
- text: ref 或 reactive
link: /frontend/vue/watch/source-type#ref-或-reactive
- text: getter 函数
link: /frontend/vue/watch/source-type#getter-函数
- text: 多个侦听源
link: /frontend/vue/watch/source-type#多个侦听源
- text: 侦听器的类型
link: /frontend/vue/watch/types
items:
Expand All @@ -92,6 +108,13 @@
link: /frontend/vue/watch/types#即时侦听
- text: 一次性侦听
link: /frontend/vue/watch/types#一次性侦听
- text: watch vs. watchEffect
link: /frontend/vue/watch/watch-effect
items:
- text: watcheffect 的使用场景
link: /frontend/vue/watch/watch-effect#watcheffect-的使用场景
- text: 比较 watch 和 watcheffect
link: /frontend/vue/watch/watch-effect#比较-watch-和-watcheffect
- text: 表单
collapsed: true
items:
Expand Down
151 changes: 140 additions & 11 deletions src/frontend/vue/watch/basic.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,155 @@

`watch 函数`在每次响应式状态变化时触发回调函数,可以执行一些“副作用”,例如:更改 DOM 元素、异步请求。

::: details 查看示例
<<< @/../projects/vue-sandbox/src/components/ComputedAndWatch/WatchBasic.vue

## 回调的触发时机

:::tip
默认情况下,侦听器回调会在父组件更新 (如有) **之后**、所属组件的 DOM 更新**之前**被调用。
:::

### Vue 更新之前触发

::: warning 注意
`{ flush: "sync" }` 每当检测到响应式数据变化时,都会立即执行回调函数。
可以用来监视简单值(例如:布尔值),但应避免在可能多次同步修改的数据源(例如:数组)上使用。
:::

::: code-group

```js [前置刷新]
watch(source, callback, {
flush: "sync",
});

watchEffect(callback, {
flush: "sync",
});
```

```js [前置刷新 watchEffect 的等价写法]
import { watchSyncEffect } from "vue";

watchSyncEffect(() => {
/* 在响应式数据变化时同步执行 */
});
```

:::

## 侦听源数据类型
### Vue 更新之后触发

::: code-group

```js [后置刷新]
watch(source, callback, {
flush: "post",
});

### ref 或 reactive
watchEffect(callback, {
flush: "post",
});
```

```js [后置刷新 watchEffect 的等价写法]
import { watchPostEffect } from "vue";

watchPostEffect(() => {
/* 在 Vue 更新后执行 */
});
```

::: details 查看示例
<<< @/../projects/vue-sandbox/src/components/ComputedAndWatch/WatchRef.vue
:::

### getter 函数
## 副作用清理

### onCleanup <Badge type="tip" text="Vue3.5 之前" />

```js
watch(id, (newId, oldId, onCleanup) => {
// ...
onCleanup(() => {
// 清理逻辑
});
});

::: details 查看示例
<<< @/../projects/vue-sandbox/src/components/ComputedAndWatch/WatchGetter.vue
watchEffect((onCleanup) => {
// ...
onCleanup(() => {
// 清理逻辑
});
});
```

### onWatcherCleanup <Badge type="tip" text="Vue3.5+" />

当侦听器失效并准备重新调用时,`onWatcherCleanup`会在下一次调用之前执行。

::: warning 注意
`onWatcherCleanup` 仅在 `Vue3.5+` 中支持。
并且必须在 `watch``watchEffect` 回调函数的同步执行期间调用,不能在异步函数的`await`语句之后调用。
:::

### 多个侦听源
```js
import { watch, onWatcherCleanup } from "vue";

watch(id, (newId) => {
const controller = new AbortController();

fetch(`/api/${newId}`, { signal: controller.signal }).then(() => {
// 回调逻辑
});

onWatcherCleanup(() => {
// 终止过期请求
controller.abort();
});
});
```

## 停止侦听

使用**同步**语句创建的侦听器,会自动绑定到宿主组件实例上,并且会在宿主组件卸载时自动停止。因此,在大多数情况下,无需关心怎么停止侦听器。

如果使用异步回调创建一个侦听器,就必须手动停止它,以防止内存泄漏。

```vue
<script setup>
import { watchEffect } from "vue";
// 它会自动停止
watchEffect(() => {});
// ...这个则不会!
setTimeout(() => {
watchEffect(() => {});
}, 100);
</script>
```

要手动停止一个侦听器,可以调用 `watch``watchEffect` 返回的函数:

```js
const unwatch = watchEffect(() => {});

// ...当该侦听器不再需要时
unwatch();
```

:::warning 注意
需要异步创建侦听器的情况很少,应尽可能选择同步创建。
如果需要等待一些异步数据,可以使用条件式的侦听逻辑:

```js
// 需要异步请求得到的数据
const data = ref(null);

watchEffect(() => {
if (data.value) {
// 数据加载后执行某些操作...
}
});
```

::: details 查看示例
<<< @/../projects/vue-sandbox/src/components/ComputedAndWatch/WatchArr.vue
:::
13 changes: 13 additions & 0 deletions src/frontend/vue/watch/source-type.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# 侦听源数据类型

## ref 或 reactive

<<< @/../projects/vue-sandbox/src/components/ComputedAndWatch/WatchRef.vue

## getter 函数

<<< @/../projects/vue-sandbox/src/components/ComputedAndWatch/WatchGetter.vue

## 多个侦听源

<<< @/../projects/vue-sandbox/src/components/ComputedAndWatch/WatchArr.vue
25 changes: 25 additions & 0 deletions src/frontend/vue/watch/watch-effect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# watch vs. watchEffect

## watchEffect 的使用场景

`watchEffect` 会自动跟踪回调中的响应式依赖,并在依赖变更时重新运行回调。

::: code-group

<<< @/../projects/vue-sandbox/src/components/ComputedAndWatch/WatchEffect.vue#snippet{js} [watchEffect]

<<< @/../projects/vue-sandbox/src/components/ComputedAndWatch/WatchEffectWatch.vue#snippet{js} [watchEffect 的等价写法]

:::

## 比较 watch 和 watchEffect

`watch` 只追踪明确侦听的数据源。仅在数据确实改变时才触发回调,因此能更精确地控制回调函数的触发时机。

`watchEffect` 会追踪回调中的所有能访问到的响应式依赖。会在副作用发生期间追踪依赖,在有多个依赖时代码会更简洁。

如果需要侦听一个嵌套数据结构中的几个属性,使用`watchEffect`可能会比深层侦听更有效,因为它只跟踪回调中被使用的属性,而不是递归地跟踪所有属性。

::: tip
`watchEffect` 仅会在同步执行期间追踪依赖。在异步执行期间,只有在第一个`await`正常工作前访问到的属性才会被追踪。
:::

0 comments on commit 694da62

Please sign in to comment.