# 计算属性和侦听器

本节使用单文件组件语法作为代码示例

# computed

传入一个 getter 函数,返回一个默认不可手动修改的 ref 对象。

const count = ref(1)
const plusOne = computed(() => count.value + 1)

console.log(plusOne.value) // 2

plusOne.value++ // 错误!
1
2
3
4
5
6

或者传入一个拥有 getset 函数的对象,创建一个可手动修改的计算状态。

const count = ref(1)
const plusOne = computed({
	get: () => count.value + 1,
	set: val => {
		count.value = val - 1
	},
})

plusOne.value = 1
console.log(count.value) // 0
1
2
3
4
5
6
7
8
9
10

类型定义:

// 只读的
function computed<T>(getter: () => T): Readonly<Ref<Readonly<T>>>

// 可更改的
function computed<T>(options: { get: () => T; set: (value: T) => void }): Ref<T>
1
2
3
4
5

# watchEffect

立即执行传入的一个函数,并响应式追踪其依赖,并在其依赖变更时重新运行该函数。

const count = ref(0)

watchEffect(() => console.log(count.value))
// -> 打印出 0

setTimeout(() => {
	count.value++
	// -> 打印出 1
}, 100)
1
2
3
4
5
6
7
8
9

类型定义:

function watchEffect(
	effect: (onInvalidate: InvalidateCbRegistrator) => void,
	options?: WatchEffectOptions
): StopHandle

interface WatchEffectOptions {
	flush?: 'pre' | 'post' | 'sync' // default: 'pre'
	onTrack?: (event: DebuggerEvent) => void
	onTrigger?: (event: DebuggerEvent) => void
}

interface DebuggerEvent {
	effect: ReactiveEffect
	target: any
	type: OperationTypes
	key: string | symbol | undefined
}

type InvalidateCbRegistrator = (invalidate: () => void) => void

type StopHandle = () => void
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

参考:watchEffect 指南

# watch

watch API 完全等效于选项 API this.$watch (以及 watch 中相应的选项)。watch 需要侦听特定的数据源,并在回调函数中执行副作用。默认情况是懒执行的,也就是说仅在侦听的源变更时才执行回调。

  • 对比 watchEffect,watch 允许我们:

    • 懒执行副作用;
    • 更明确哪些状态的改变会触发侦听器重新运行副作用;
    • 访问侦听状态变化前后的值。

# 侦听单个数据源

侦听器的数据源可以是一个拥有返回值的 getter 函数,也可以是 ref

// 侦听一个 getter
const state = reactive({ count: 0 })
watch(
	() => state.count,
	(count, prevCount) => {
		/* ... */
	}
)

// 直接侦听一个 ref
const count = ref(0)
watch(count, (count, prevCount) => {
	/* ... */
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 侦听多个数据源

watcher 也可以使用数组来同时侦听多个源:

watch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar]) => {
	/* ... */
})
1
2
3

#watchEffect 共享的行为

watch 和 watchEffect 在停止侦听, 清除副作用 (相应地 onInvalidate 会作为回调的第三个参数传入),副作用刷新时机侦听器调试 等方面行为一致.

类型定义:

// 侦听单数据源
function watch<T>(
  source: WatcherSource<T>,
  callback: (
    value: T,
    oldValue: T,
    onInvalidate: InvalidateCbRegistrator
  ) => void,
  options?: WatchOptions
): StopHandle

// 侦听多数据源
function watch<T extends WatcherSource<unknown>[]>(
  sources: T
  callback: (
    values: MapSources<T>,
    oldValues: MapSources<T>,
    onInvalidate: InvalidateCbRegistrator
  ) => void,
  options? : WatchOptions
): StopHandle

type WatcherSource<T> = Ref<T> | (() => T)

type MapSources<T> = {
  [K in keyof T]: T[K] extends WatcherSource<infer V> ? V : never
}

// 共有的属性 请查看 `watchEffect` 的类型定义
interface WatchOptions extends WatchEffectOptions {
  immediate?: boolean // default: false
  deep?: boolean
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

参考watch 指南