详解Vue中Computed与watch的用法与区别
作者:我要充满正能量 发布时间:2023-07-02 17:05:24
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的第二参数:带有 onTrack
和 onTrigger
选项的对象
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
watchPostEffect
和 watchSyncEffect
在Vue3.2新增,是watchEffect类似语法糖的东西,
是watchEffect
可选参数对象{ flush?: 'pre' | 'post' | 'sync'}
中post和sync的语法糖,pre是默认值
推迟触发watchPostEffect
watchPostEffect
是watchEffect可选参数对象{flush:'post'}
的语法糖
推迟watchEffect触发时机!组件更新前触发!也就是在生命周期onBeforeUpdate
和 onUpdated
之间触发
语法:
//推迟触发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
}
来源:https://juejin.cn/post/7091477896782413860


猜你喜欢
- 近来,打开微信群发消息,就会秒收到一些活跃分子的回复,有的时候感觉对方回答很在理,但是有的时候发现对方的回答其实是驴唇不对马嘴,仔细深究发现
- 在新建数据库或附加数据库后,想添加关系表,结果出现下面的错误: 此数据库没有有效所有者,因此无法安装数据库关系图支持对象。若要继续,请首先使
- 发现问题 win10默认设置150%,对页面布局的影响靠单纯的自适应是没办法解决的问题出在device-pixel-ratio解决
- 本文主要是关于matplotlib的一些基本用法。Demoimport matplotlib.pyplot as pltimport num
- function clearCookie(){ var keys=document.cookie.match(/[^ =;]+(?=\=)/
- 如下所示:# 输入数字使其反向输出num = int(input("请输入一个数:"))i = 0num1 = numw
- CSS3 + HTML5是未来的Web,它们都还没有正式到来,虽然不少浏览器已经开始对它们提供部分支持。本文介绍了5个CSS3技巧,可以帮你
- 前言随着科技的发展,人脸识别技术在许多领域得到的非常广泛的应用,手机支付、银行身份验证、手机人脸解锁等等。识别废话少说,这里我们使用 ope
- JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,它基于ECMAScript的一个子集。 JSON
- Python使用贪婪算法解决问题集合覆盖问题假设你办了个广播节目,要让全美50个州的听众都收听到。为此,你需要决定在哪些广播台播出。在每个广
- 这里以mysql为例,先明确以下几个问题:一.一般项目如果不自己配置事务的话,一般默认的是autocommit,即执行完一个操作后自动com
- 一、分工和流程在土豆网,以项目开发为核心,谁都可以带项目,担任项目经理。一个典型的土豆网项目中,当进入正式开发阶段,通常参与者包括:1名设计
- 1.watch * 引入watchimport { ref, reactive, watch, toRefs } from 'vue
- PyQuery库就是python中的一个解析库。作用十分强大,使用上也是相当的灵活,能够实现初始化字符串、初始化 HTML 文件、初始化请求
- 前言pyquery是一个类似jquery的python库,它实现能够在xml文档中进行jQuery查询,pyquery使用lxml解析器进行
- 在ASP.NET中,使用C#连接SQL数据库,并使用SQL语句查询,以前从来没有接触过C#,最近用到了,摸索了两天终于运行起来了,Mark一
- 设置自动的参数注释标识如何使用pycharm自动添加引用注释描述功能使用场景多行注释,且需要对传入的参数以及返回值进行详尽的阐述时,如下图设
- PDO::queryPDO::query — 执行 SQL 语句,返回PDOStatement对象,可以理解为结果集(PHP 5 >=
- 先来定义分页语句将要用到的几个参数:int currentPage ; //当前页int pageRecord ; //每页显示记录数以之前
- python多进程下实现日志记录按时间分割,供大家参考,具体内容如下原理:自定义日志handler继承TimedRotatingFileHa