响应性 API:核心
ref()
接收一个内部值并返回一个响应性和可变的 ref 对象,该对象具有一个指向内部值的单属性 .value
。
类型
tsfunction ref<T>(value: T): Ref<UnwrapRef<T>> interface Ref<T> { value: T }
详情
ref 对象是可变的 - 即您可以分配新的值给
.value
。它也是响应性的 - 即对.value
的任何读取操作都会被跟踪,写入操作将触发相关效果。如果将对象分配为 ref 的值,则对象会通过 reactive() 被转换为深度响应性。这也意味着如果对象包含嵌套的 ref,它们将被深度展开。
为了避免深度转换,请使用
shallowRef()
。示例
jsconst count = ref(0) console.log(count.value) // 0 count.value = 1 console.log(count.value) // 1
另请参阅
computed()
接收一个 getter 函数 并返回一个只读响应性 ref 对象,该对象包含从 getter 返回的值。它还可以接收一个具有 get
和 set
函数的对象来创建可写的 ref 对象。
类型
ts// read-only function computed<T>( getter: (oldValue: T | undefined) => T, // see "Computed Debugging" link below debuggerOptions?: DebuggerOptions ): Readonly<Ref<Readonly<T>>> // writable function computed<T>( options: { get: (oldValue: T | undefined) => T set: (value: T) => void }, debuggerOptions?: DebuggerOptions ): Ref<T>
示例
创建只读计算 ref
jsconst count = ref(1) const plusOne = computed(() => count.value + 1) console.log(plusOne.value) // 2 plusOne.value++ // error
创建可写计算 ref
jsconst count = ref(1) const plusOne = computed({ get: () => count.value + 1, set: (val) => { count.value = val - 1 } }) plusOne.value = 1 console.log(count.value) // 0
调试
jsconst plusOne = computed(() => count.value + 1, { onTrack(e) { debugger }, onTrigger(e) { debugger } })
另请参阅
reactive()
返回对象的响应式代理。
类型
tsfunction reactive<T extends object>(target: T): UnwrapNestedRefs<T>
详情
响应式转换是“深层”的:它影响所有嵌套属性。响应式对象在保持响应性的同时,也会深度展开任何引用属性。
需要注意的是,当引用作为响应式数组或原生集合类型(如
Map
)的元素访问时,不会执行引用展开。为了避免深度转换并仅在根级别保留响应性,请使用shallowReactive()。
返回的对象及其嵌套对象被ES Proxy包装,并且与原始对象不等价。建议仅使用响应式代理并避免依赖于原始对象。
示例
创建响应式对象
jsconst obj = reactive({ count: 0 }) obj.count++
引用展开
tsconst count = ref(1) const obj = reactive({ count }) // ref will be unwrapped console.log(obj.count === count.value) // true // it will update `obj.count` count.value++ console.log(count.value) // 2 console.log(obj.count) // 2 // it will also update `count` ref obj.count++ console.log(obj.count) // 3 console.log(count.value) // 3
请注意,当引用作为数组或集合元素访问时,引用不会被展开
jsconst books = reactive([ref('Vue 3 Guide')]) // need .value here console.log(books[0].value) const map = reactive(new Map([['count', ref(0)]])) // need .value here console.log(map.get('count').value)
当将引用赋值给
reactive
属性时,该引用也将自动展开tsconst count = ref(1) const obj = reactive({}) obj.count = count console.log(obj.count) // 1 console.log(obj.count === count.value) // true
另请参阅
readonly()
接受一个对象(响应式或纯对象)或一个引用,并返回对原始对象的只读代理。
类型
tsfunction readonly<T extends object>( target: T ): DeepReadonly<UnwrapNestedRefs<T>>
详情
只读代理是深层的:访问的任何嵌套属性也将是只读的。它还具有与
reactive()
相同的引用展开行为,除了展开的值也将变为只读。为了避免深度转换,请使用shallowReadonly()。
示例
jsconst original = reactive({ count: 0 }) const copy = readonly(original) watchEffect(() => { // works for reactivity tracking console.log(copy.count) }) // mutating original will trigger watchers relying on the copy original.count++ // mutating the copy will fail and result in a warning copy.count++ // warning!
watchEffect()
立即运行一个函数,同时响应式地跟踪其依赖项,并在依赖项更改时重新运行它。
类型
tsfunction watchEffect( effect: (onCleanup: OnCleanup) => void, options?: WatchEffectOptions ): WatchHandle type OnCleanup = (cleanupFn: () => void) => void interface WatchEffectOptions { flush?: 'pre' | 'post' | 'sync' // default: 'pre' onTrack?: (event: DebuggerEvent) => void onTrigger?: (event: DebuggerEvent) => void } interface WatchHandle { (): void // callable, same as `stop` pause: () => void resume: () => void stop: () => void }
详情
第一个参数是要运行的效应函数。效应函数接收一个函数,可用于注册清理回调。清理回调将在下一次效应重新运行之前被调用,并可用于清理无效的副作用,例如挂起的异步请求(见以下示例)。
第二个参数是一个可选的选项对象,可用于调整效应的刷新时间或调试效应的依赖项。
默认情况下,观察者将在组件渲染之前运行。将
flush: 'post'
设置为将观察者推迟到组件渲染之后。有关更多信息,请参阅回调刷新时间。在罕见的情况下,可能需要在响应式依赖项更改时立即触发观察者,例如,以使缓存无效。这可以通过使用flush: 'sync'
来实现。然而,此设置应谨慎使用,因为它可能导致在同时更新多个属性时出现性能和数据一致性方面的问题。返回值是一个处理函数,可以调用它以停止效应再次运行。
示例
jsconst count = ref(0) watchEffect(() => console.log(count.value)) // -> logs 0 count.value++ // -> logs 1
停止观察者
jsconst stop = watchEffect(() => {}) // when the watcher is no longer needed: stop()
暂停/恢复观察者:
jsconst { stop, pause, resume } = watchEffect(() => {}) // temporarily pause the watcher pause() // resume later resume() // stop stop()
副作用清理
jswatchEffect(async (onCleanup) => { const { response, cancel } = doAsyncWork(newId) // `cancel` will be called if `id` changes, cancelling // the previous request if it hasn't completed yet onCleanup(cancel) data.value = await response })
3.5+中的副作用清理
jsimport { onWatcherCleanup } from 'vue' watchEffect(async () => { const { response, cancel } = doAsyncWork(newId) // `cancel` will be called if `id` changes, cancelling // the previous request if it hasn't completed yet onWatcherCleanup(cancel) data.value = await response })
选项
jswatchEffect(() => {}, { flush: 'post', onTrack(e) { debugger }, onTrigger(e) { debugger } })
另请参阅
watchPostEffect()
watchEffect()
的别名,带有flush: 'post'
选项。
watchSyncEffect()
watchEffect()
的别名,带有flush: 'sync'
选项。
watch()
观察一个或多个响应式数据源,并在数据源更改时调用回调函数。
类型
ts// watching single source function watch<T>( source: WatchSource<T>, callback: WatchCallback<T>, options?: WatchOptions ): WatchHandle // watching multiple sources function watch<T>( sources: WatchSource<T>[], callback: WatchCallback<T[]>, options?: WatchOptions ): WatchHandle type WatchCallback<T> = ( value: T, oldValue: T, onCleanup: (cleanupFn: () => void) => void ) => void type WatchSource<T> = | Ref<T> // ref | (() => T) // getter | (T extends object ? T : never) // reactive object interface WatchOptions extends WatchEffectOptions { immediate?: boolean // default: false deep?: boolean | number // default: false flush?: 'pre' | 'post' | 'sync' // default: 'pre' onTrack?: (event: DebuggerEvent) => void onTrigger?: (event: DebuggerEvent) => void once?: boolean // default: false (3.4+) } interface WatchHandle { (): void // callable, same as `stop` pause: () => void resume: () => void stop: () => void }
为了可读性,类型已简化。
详情
watch()
默认是懒加载的 - 即只有当被观察的源发生变化时,回调才会被调用。第一个参数是观察者的 源。源可以是以下之一
- 一个返回值的 getter 函数
- 一个 ref
- 一个响应式对象
- ...或者以上任意类型的数组。
第二个参数是在源发生变化时被调用的回调函数。回调函数接收三个参数:新值、旧值以及一个用于注册副作用清理回调函数的函数。清理回调函数将在下一次副作用重新运行之前被调用,可以用来清理无效的副作用,例如挂起的异步请求。
当观察多个源时,回调函数接收包含新/旧值的两个数组,这些值对应于源数组。
第三个可选参数是一个支持以下选项的选项对象
immediate
:在观察者创建时立即触发回调。第一次调用时,旧值将是undefined
。deep
:如果源是对象,强制进行深度遍历,以便在深度突变时触发回调。在 3.5+ 中,这也可以是一个表示最大遍历深度的数字。参见 深度观察者。flush
:调整回调的刷新时间。参见 回调刷新时间 和watchEffect()
。onTrack / onTrigger
:调试观察者的依赖关系。参见 观察者调试。once
:(3.4+)只运行一次回调。第一次回调运行后,观察者将自动停止。
与
watchEffect()
相比,watch()
允许我们- 懒加载副作用;
- 更具体地指定哪些状态应该触发观察者重新运行;
- 访问被观察状态的当前值和旧值。
示例
观察 getter
jsconst state = reactive({ count: 0 }) watch( () => state.count, (count, prevCount) => { /* ... */ } )
观察 ref
jsconst count = ref(0) watch(count, (count, prevCount) => { /* ... */ })
当观察多个源时,回调函数接收包含新/旧值的数组,这些值对应于源数组
jswatch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar]) => { /* ... */ })
当使用 getter 源时,只有当 getter 的返回值发生变化时,观察者才会触发。如果您希望在深度突变时触发回调,需要显式地将观察者强制进入深度模式,使用
{ deep: true }
。注意,在深度模式下,如果回调是由深度突变触发的,新值和旧值将是相同的对象jsconst state = reactive({ count: 0 }) watch( () => state, (newValue, oldValue) => { // newValue === oldValue }, { deep: true } )
当直接观察响应式对象时,观察者自动处于深度模式
jsconst state = reactive({ count: 0 }) watch(state, () => { /* triggers on deep mutation to state */ })
watch()
与watchEffect()
具有相同的刷新时间和调试选项jswatch(source, callback, { flush: 'post', onTrack(e) { debugger }, onTrigger(e) { debugger } })
停止观察者
jsconst stop = watch(source, callback) // when the watcher is no longer needed: stop()
暂停/恢复观察者:
jsconst { stop, pause, resume } = watch(() => {}) // temporarily pause the watcher pause() // resume later resume() // stop stop()
副作用清理
jswatch(id, async (newId, oldId, onCleanup) => { const { response, cancel } = doAsyncWork(newId) // `cancel` will be called if `id` changes, cancelling // the previous request if it hasn't completed yet onCleanup(cancel) data.value = await response })
3.5+中的副作用清理
jsimport { onWatcherCleanup } from 'vue' watch(id, async (newId) => { const { response, cancel } = doAsyncWork(newId) onWatcherCleanup(cancel) data.value = await response })
另请参阅
onWatcherCleanup()
注册一个清理函数,在当前观察者即将重新运行时执行。只能在同步执行 watchEffect
副作用函数或 watch
回调函数时调用(即不能在异步函数中的 await
语句之后调用。)
类型
tsfunction onWatcherCleanup( cleanupFn: () => void, failSilently?: boolean ): void
示例
tsimport { watch, onWatcherCleanup } from 'vue' watch(id, (newId) => { const { response, cancel } = doAsyncWork(newId) // `cancel` will be called if `id` changes, cancelling // the previous request if it hasn't completed yet onWatcherCleanup(cancel) })