详解Vue中Computed与watch的用法与区别

详解Vue中Computed与watch的用法与区别

目录

computed

computed只接收一个getter函数

computed同时接收getter函数对象和setter函数对象

调试 Computed

watchEffect

立即执行 监听基本数据类型

停止watchEffect

清理watchEffect

watchPostEffect 和 watchSyncEffect

watchEffect不能监听对象

watch

监听单个数据

监听多个数据(传入数组)

官方文档总结

computed

watchEffect

watch

computed computed只接收一个getter函数

1、getter必须有返回值

2、computed返回一个只读响应式ref对象 (只读、响应式、对象)

注意:omputed只接收一个getter函数时,返回的只读对象,也就是不能修改他的返回值!

getter触发条件

1、computed返回值首次被读取时

2、getter绑定的响应式变量被修改时

<script setup> import { ref,computed } from 'vue' const num = ref(1) //computed返回一个只读响应式ref对象computedNum //computedNum是只读属性 let computedNum = computed(() => num.value + 1) </script> ​ <template> <p> num:{{ num }} </p> <p>computedNum:{{ computedNum }}</p> <!-- 修改响应式变量num 触发与之绑定的computed的getter--> <button @click="num++">num++</button> <!-- computedNum是只读属性--> <button @click="computedNum++">computedNum++</button> </template> computed同时接收getter函数对象和setter函数对象

1、setter函数对象没有返回值

2、computed返回一个可读可写响应式对象

3、setter函数对象有参数,是getter的返回值,也是computed的值

4、修改computed返回值,触发setter函数对象执行,但不会真正修改computed返回值(setter内改变getter计算值就会改变computed返回值)

setter触发条件

computed返回值被修改时

实例:

<script setup> import { ref, computed } from 'vue' const num = ref(1) //getter(只读) let computedNum = computed(() => num.value + 1) //getter和setter (可读可写) let computedNum2 = computed({ get: () => num.value + 1, set: (val) => { console.log(val); //setter中修改ref响应式变量num,将触发关联的num的getter计算 //computedNum和computedNum2的getter同时触发 num.value++ } }) </script> ​ <template> <p> num:{{ num }} </p> <p>computedNum:{{ computedNum }}</p> <p>computedNum2:{{ computedNum2 }}</p> <button @click="num++">num++</button> <!-- computedNum是只读属性,会有警告提醒 Write operation failed: computed value is readonly--> <button @click="computedNum++">computedNum++</button> <!-- computedNum2是可读可写属性--> <button @click="computedNum2++">computedNum2++</button> </template> 调试 Computed

使用范围:仅开发模式生效

computed的第二参数:带有 onTrackonTrigger 选项的对象

onTrack :getter关联的响应式数据时触发。

onTrigger :getter关联的响应式数据被修改时触发

<script setup> import { ref, computed } from 'vue' const num = ref(1) let computedNum = computed(() => num.value + 1, { onTrack: (e) => { console.log('onTrack'); console.log(e); }, onTrigger: (e) => { console.log('onTrigger'); console.log(e); } }) ​ </script> ​ <template> <p> num:{{ num }} </p> <p>computedNum:{{ computedNum }}</p> <!--每次 num++将触发onTrigger --> <button @click="num++">num++</button> </template> watchEffect

语法:

参数1:触发监听回调函数,回调函数可传入一个onInvalidate函数作为参数!

可选参数2:对象,包含3个可选属性flush、onTrack、onTrigger

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

1、会立即执行一次(和watch的immediate属性效果一致)

2、关联的响应式数据被修改时触发

3、会自动感知代码依赖,和watch不一样,watchEffect会主动绑定监听数据

局限性:不能监听对象(但可以监听对象的属性),只能监听类似ref基本数据类型的响应式数据

立即执行 监听基本数据类型 <script setup> import { ref, watchEffect } from 'vue' const num = ref(1) //会立即执行一次 watchEffect(() => { console.log('watchEffect'); num.value++ }) </script> ​ <template> <p>num: {{ num }}</p> <button @click="num++">num++</button> </template> 停止watchEffect

隐式:组件卸载时自动停止

显式:调用watchEffect 返回值

const stop = watchEffect(() => { /* ... */ }) ​ // 显式停止 stop() 清理watchEffect

语法: watchEffect( onInvalidate=>{ onInvalidate(()=>{ }) })

onInvalidate 是一个函数!优先触发!

onInvalidate 执行时机:

1、watchEffect被重新触发时

2、组件卸载时

注意:关联的响应式数据首次被修改时不会触发onInvalidate函数!

作用: 清理定时器、事件监听removeEventListener 。。。

import { ref, watchEffect } from 'vue' const num = ref(1) watchEffect((onInvalidate ) => { console.log('watchEffect-1'); num.value++ onInvalidate (()=>{ console.log('onInvalidate-2'); }) console.log('watchEffect-3'); }) ​ //1、watchEffect 被重新触发时 // onInvalidate-2 // watchEffect-1 // watchEffect-3 //2、组件卸载时 // onInvalidate-2 //3、关联的响应式数据首次被修改(组件被挂载时) // watchEffect-1 // watchEffect-3 watchPostEffect 和 watchSyncEffect

watchPostEffectwatchSyncEffect在Vue3.2新增,是watchEffect类似语法糖的东西,

watchEffect可选参数对象{ flush?: 'pre' | 'post' | 'sync'}中post和sync的语法糖,pre是默认值

推迟触发watchPostEffect

watchPostEffect 是watchEffect可选参数对象{flush:'post'}的语法糖

推迟watchEffect触发时机!组件更新前触发!也就是在生命周期onBeforeUpdateonUpdated之间触发

语法:

//推迟触发watchEffect watchEffect( () => { /* ... */ }, { flush: 'post' } ) //Vue3.2语法糖watchPostEffect watchPostEffect(()=>{ /* ... */ })

实例:

//实验watchEffect第二参数 flush: 'post'属性 watchEffect(() => { console.log("实验watchEffect第二参数 {flush: 'post'}属性"); console.log(obj.age); },{ flush:'post' }) watchEffect(() => { console.log("watchEffect正常时机触发"); console.log(obj.age); }) //生命周期onUpdated onUpdated(()=>{ console.log('onUpdated()'); }) //生命周期onBeforeUpdate onBeforeUpdate(()=>{ console.log('onBeforeUpdate()'); })

修改obj.age时,执行结果:

watchEffect正常时机触发
onBeforeUpdate()
实验watchEffect第二参数 {flush: 'post'}属性
onUpdated()

同步触发watchSyncEffect

watchSyncEffect 是watchEffect可选参数对象{flush:'sync'}的语法糖

强制效果始终同步触发!效率低!也就是默认watchEffect之前触发

语法:

watchEffect( () => { /* ... */ }, { flush: 'sync' } ) //Vue3.2语法糖watchSyncEffect watchSyncEffect(()=>{ /* ... */ }) watchEffect不能监听对象 //假设修改了对象的属性值-修改了obj.age const obj = reactive({ name: '小明', age: 18 }) //watchEffect不能监听对象变化 watchEffect(() => { console.log('watchEffect监听对象变化'); console.log(obj); }) //watchEffect可以监听对象属性变化 watchEffect(() => { console.log('watchEffect监听对象属性变化'); console.log(obj.age); }) //watch监听对象变化 watch(obj, (obj) => { console.log('watch监听对象变化'); console.log(obj); })

总结:watchEffect用来监听能监听基本数据类型,不能监听对象,但能监听对象的属性;watch能监听基本数据类型和对象!

watch

语法:

参数1-被监听数据(形式:单个数据、数组、带返回值的回调函数)

参数2-触发监听的回调函数,无返回值

可选参数3-对象{immediate: true,deep:true},对象含2个可选参数和Vue2参数效果一致

Vue3的watch和Vue2的watch是基本一样的

1、需要指定监听数据

2、惰性,只在被监听数据变化时才触发(immediate属性可以设置在初始化的时候触发)

监听单个数据

参数1被监听数据的形式:

1、单个基本数据类型;

2、回调函数:返回值为单个基本数据类型;

// 侦听一个 getter //被监听数据传入一个带返回值的回调函数 const state = reactive({ count: 0 }) watch( () => state.count, (count, prevCount) => { /* ... */ } ) ​ // 直接侦听一个 ref const count = ref(0) watch(count, (count, prevCount) => { /* ... */ }) 监听多个数据(传入数组) watch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar]) => { /* ... */ }) 官方文档总结

以下代码截取官方文档,从TS代码可以看出很多关于watch和watchEffect函数参数和返回值的细节!

computed

computed只接收一个getter函数

getter触发条件:

1、computed返回值首次被读取时

2、getter绑定的响应式变量被修改时

computed同时接收getter函数对象和setter函数对象

setter触发条件:computed返回值被修改时

// 只读的 function computed<T>( getter: () => T, debuggerOptions?: DebuggerOptions ): Readonly<Ref<Readonly<T>>> ​ // 可写的 function computed<T>( options: { get: () => T set: (value: T) => void }, debuggerOptions?: DebuggerOptions ): Ref<T> interface DebuggerOptions { onTrack?: (event: DebuggerEvent) => void onTrigger?: (event: DebuggerEvent) => void } interface DebuggerEvent { effect: ReactiveEffect target: any type: OperationTypes key: string | symbol | undefined } watchEffect

参数1-触发监听回调函数,回调函数可传入一个onInvalidate函数作为参数!

可选参数2-对象,包含3个可选属性flush、onTrack、onTrigger

function watchEffect( effect: (onInvalidate: InvalidateCbRegistrator) => void, options?: WatchEffectOptions ): StopHandle ​ interface WatchEffectOptions { flush?: 'pre' | 'post' | 'sync' // 默认:'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 watch

参数1-被监听数据(形式:单个数据、数组、带返回值的回调函数)

参数2-触发监听的回调函数,无返回值

参数3-传入{immediate: true,deep:true}对象和Vue2参数效果一致

// 侦听单一源 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 // 默认:false deep?: boolean }

以上就是详解Vue中Computed与watch的用法与区别的详细内容,更多关于Vue Computed watch的资料请关注易知道(ezd.cc)其它相关文章!

推荐阅读