# Computed 与 Watch
# computed
接受一个 getter 函数,并根据 getter 的返回值返回一个不可变的响应式 ref 对象。
const count = ref(1)
const plusOne = computed(() => count.value + 1)
console.log(plusOne.value) // 2
plusOne.value++ // 错误
或者接受一个具有 get 和 set 函数的对象,用来创建可写的 ref 对象。
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
类型声明:
// 只读形式
function computed<T>(
getter: () => T
): Readonly<Ref<Readonly<T>>>
// 可写形式
function computed<T>(
options: {
get: () => T
set: (value: T) => void
}
): Ref<T>
# watchEffect
立即执行传入的函数,同时对其依赖进行响应式追踪,并在其依赖变更时重新运行该函数。
const count = ref(0)
watchEffect(() => console.log(count.value))
// -> logs 0
setTimeout(() => {
count.value++
// -> logs 1
}, 100)
- 停止侦听
const stop = watchEffect(() => {
/* ... */
})
// later
stop()
- 清除副作用
侦听副作用传入的函数可以接收一个函数作入参,用来注册清理回调,清理回调会在该副作用下一次执行前被调用, 可以用来清理无效的副作用,例如等待中的异步请求
watchEffect(async (onCleanup) => {
const { response, cancel } = doAsyncWork(id.value)
// `cancel` 会在 `id` 更改时调用
// 以便取消之前未完成的请求
onCleanup(cancel)
data.value = await response
})
- 副作用刷新时机
响应式系统会进行副作用函数缓存,并异步地刷新执行他们
组件的 update 函数也是一个被侦听的副作用。当一个用户定义的副作用函数进入队列时,默认情况下,会在所有的组件 update 前执行, 在watchEffect的第二个参数中,我们可以传入flush来进行副作用刷新时机调整
// 默认为 pre
watchEffect(callback, {
flush: 'pre'
})
// 侦听器回调中能访问被更新之后的DOM
// 注意:这也将推迟副作用的初始运行,直到组件的首次渲染完成。
watchEffect(callback, {
flush: 'post'
})
// 强制同步触发, 十分低效
watchEffect(callback, {
flush: 'sync'
})
类型声明:
function watchEffect(
effect: (onInvalidate: InvalidateCbRegistrator) => void,
options?: WatchEffectOptions
): StopHandle
interface WatchEffectOptions {
flush?: 'pre' | 'post' | 'sync' // 默认:'pre'
}
type InvalidateCbRegistrator = (invalidate: () => void) => void
type StopHandle = () => void
# watchSyncEffect
watchEffect 的别名,带有 flush: 'sync' 选项。
# watchPostEffect
watchEffect 的别名,带有 flush: 'post' 选项。
# watch
该 API 与选项式 API 中的 watch 基本等效,watch 需要侦听特定的数据源,并在单独的回调函数中执行副作用。默认情况下 是惰性的——即回调仅在侦听源发生变化时被调用。
与 watchEffect 比较,watch 允许我们:
- 懒执行副作用;
- 更具体地说明什么状态应该触发侦听器重新运行;
- 访问侦听状态变化前后的值。
类型声明:
// 侦听单一源
function watch<T>(
source: WatcherSource<T>,
callback: (
value: T,
oldValue: T,
onInvalidate: InvalidateCbRegistrator
) => void,
options?: WatchOptions
): StopHandle
// 侦听多个源
type WatcherSource<T> = Ref<T> | (() => T)
type InvalidateCbRegistrator = (invalidate: () => void) => void
type StopHandle = () => void
interface WatchOptions extends WatchEffectOptions {
immediate?: boolean // 默认:false
deep?: boolean // 默认:false
immediateAsync: boolean // 默认:false
}
# 侦听单一源
watch 可以侦听一个具有返回值的 getter,也可以直接是一个 ref
// 侦听一个 getter
const state = reactive({ count: 0 })
watch(
() => state.count,
(count, prevCount) => {
/* ... */
}
)
// 直接侦听ref
const count = ref(0)
watch(count, (count, prevCount) => {
/* ... */
})
# 侦听多个源
还可以使用数组的形式同时侦听多个数据源:
import { watch } from '@mpxjs/core'
watch([aRef, bRef], ([a, b], [prevA, prevB]) => {
/* ... */
})
# 与 watchEffect 相同的行为
watch 与 watchEffect 在手动停止侦听、清除副作用、副作用刷新时机方面有相同的行为。
import { watch } from '@mpxjs/core'
let unwatch = watch(() => {
return a.value + b.value
}, (newVal, oldVal) => {
// 做点什么
})
// 调用返回值unwatch可以取消观察
unwatch()
# watch 选项
选项:deep
为了发现对象内部值的变化,可以在选项参数中指定 deep: true。
import {watch} from '@mpxjs/core' watch(() => { return this.someObject }, () => { // 回调函数 }), { deep: true }) this.someObject.nestedValue = 123 // callback is fired
选项:once
在选项参数中指定
once: true
该回调方法只会执行一次,后续的改变将不会触发回调;
该参数也可以是函数,若函数返回值为true
时,则后续的改变将不会触发回调import {watch} from '@mpxjs/core' watch(() => { return this.a }, () => { // 该回调函数只会执行一次 }, { once: true }) // 当 once 是函数时 watch(() => { return this.a }, (val, newVal) => { // 当 val 等于2时,this.a 的后续改变将不会被监听 }, { once: (val, oldVal) => { if (val == 2) { return true } } })
选项:immediate
在选项参数中指定
immediate: true
将立即以表达式的当前值触发回调。import {watch} from '@mpxjs/core' watch(() => { return this.a }, () => { // 回调函数 }), { immediate: true }) // 立即以 `this.a` 的当前值触发回调
注意在带有 immediate 选项时,你不能在第一次回调时取消侦听。
import {watch} from '@mpxjs/core' var unwatch = watch(() => { return this.a }, () => { unwatch() // 这会导致报错! }), { immediate: true })
如果你仍然希望在回调内部调用取消侦听的函数,你应该先检查其可用性。
import {watch} from '@mpxjs/core' var unwatch = watch(() => { return this.a }, () => { if (unwatch) { // 请先检查其可用性! unwatch() } }), { immediate: true })
← Refs Effect 作用域 API →