第 4 章:computed / watch
学习目标
- 用
computed派生数据 - 区分
watch/watchEffect适用场景 - 控制
watch的immediate/deep/flush - 避开监听不到变化的 4 个坑
一、computed:派生数据(有缓存)
vue
<script setup lang="ts">
import { ref, computed } from 'vue'
const list = ref([1, 2, 3, 4])
const sum = computed(() => list.value.reduce((a, b) => a + b, 0))
const doubled = computed({
get: () => list.value.map(x => x * 2),
set: v => list.value = v.map(x => x / 2), // 可写
})
</script>
<template>
<p>合计:{{ sum }}</p>
<p>双倍:{{ doubled }}</p>
</template>computed 只在依赖变化时重算一次,模板多次访问不会重复执行。
⚠️ 坑 1:
computed里不要改其他响应式状态,会形成循环依赖。
二、watch:监听到变化后做事
vue
<script setup lang="ts">
import { ref, watch } from 'vue'
const id = ref(1)
const user = ref<{ name: string } | null>(null)
// 1. 监听 ref
watch(id, (newVal, oldVal) => {
console.log('id 改变', newVal, oldVal)
})
// 2. 立即执行 + 深度监听
watch(user, () => fetchUser(), {
immediate: true,
deep: true,
})
// 3. 监听多个源
watch([id, () => user.value?.name], ([nid, nname]) => {
console.log(nid, nname)
})三、watchEffect:自动收集依赖
vue
<script setup lang="ts">
import { ref, watchEffect } from 'vue'
const url = ref('/api/list')
const data = ref(null)
watchEffect(async () => {
// 自动追踪 url.value
const res = await fetch(url.value)
data.value = await res.json()
})watchEffect 立即执行一次,体内用到的 ref 自动成为依赖。
四、flush 时机
| 选项 | 触发时机 |
|---|---|
'pre' (默认) | 组件更新前 |
'post' | 组件更新后 |
'sync' | 同步,极少用 |
ts
watch(source, cb, { flush: 'post' }) // DOM 已更新五、停止监听
ts
const stop = watchEffect(() => {...})
stop() // 手动停止
// 或在 onScopeDispose 中停
import { getCurrentScope, onScopeDispose } from 'vue'
onScopeDispose(() => stop())⚠️ 坑 2:
watch监听 reactive 对象时,默认deep: true,无需再写。 ⚠️ 坑 3:监听reactive的基本类型字段要传函数:() => state.count,直接写state.count不会触发(因为值是基本类型,需要 getter)。 ⚠️ 坑 4:watch回调里不要解构 reactive,会丢失响应性。
六、实战:防抖搜索
vue
<script setup lang="ts">
import { ref, watch } from 'vue'
const keyword = ref('')
const result = ref([])
let timer: number | undefined
watch(keyword, (val) => {
clearTimeout(timer)
timer = setTimeout(async () => {
result.value = await api.search(val)
}, 300)
})
</script>七、本章小结
| API | 用途 |
|---|---|
computed | 派生数据,有缓存,只读/可写 |
watch | 显式声明源,新旧值监听 |
watchEffect | 自动收集依赖,写法短 |
flush: 'post' | DOM 更新后触发 |
immediate / deep | 立即执行 / 深度监听 |
动手练习
- 价格计算:用
computed实现price * count + 运费 - 持久化:用
watch监听count,变化时localStorage.setItem - 搜索:用
watchEffect+setTimeout实现 300ms 防抖
下一章:第 5 章:组件基础 →