Vue3中的computed,watch和watchEffect的特点

本文详细介绍了Vue.js中的computed和watch特性,包括computed的缓存机制、只读性、同步执行以及watch的监听前/后值、深度监听、异步处理和初始化行为。对比了它们在性能和应用场景上的差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.computed
1)computed拥有缓存性,多次调用会直接从缓存中获取,而不会重新执行,只有相依赖的数据发生改变才会重新计算,所以说computed性能很高。
例:下面是同时调用三次计算属性firstTotal和三次函数firstTotalFun()的运行结果。可以发现,函数被执行了三次,而计算属性只被执行了一次。
在这里插入图片描述
代码:

<template>
	<view class="container">
	<view class="item">
		<view>商品:</view>
		<input type="text" v-model="firstGoods">
	</view>
	<view class="item">
		<view>价格:</view>
		<input type="text" v-model="firstPrice">
	</view>
	<view class="item">
		<view>数量:</view>
		<input type="text" v-model="firstNum">
	</view>
	<view class="item">
		<view>总价格:</view>
		<view>{{firstTotal}}, {{firstTotalFun()}}</view>
		<view>{{firstTotal}}, {{firstTotalFun()}}</view>
		<view>{{firstTotal}}, {{firstTotalFun()}}</view>
	</view>
	</view>
</template>
<script setup>
import { computed,ref } from 'vue';
let firstNum = ref(0)
let firstGoods = ref('')
let firstPrice = ref(0)
//计算属性
const firstTotal = computed(()=>{console.log("computed调用了");
 return firstPrice.value*firstNum.value})
 //普通函数
const firstTotalFun = ()=>{
	console.log("Function调用了")
	return firstPrice.value*firstNum.value
}
</script>

2)computed是只读的,不要去修改它,会报警告。
结果:
在这里插入图片描述
代码:
在这里插入图片描述
3)computed只能进行同步操作
4)computed在页面初始化加载的时候就会被立刻调用
5)必须要有返回值(return),如果代码只有一行也可以使用简写。

//正常写法
const firstTotal = computed(()=>{return firstPrice.value*firstNum.value})
//简写
const firstTotal = computed(()=>firstPrice.value*firstNum.value)

2.watch
1)watch可以监听到前一次的值和最新值。
结果:
在这里插入图片描述
代码:

let firstWatch = ref(0);
watch(firstWatch, (newValue,oldValue)=>{
	console.log("调用了watch:",newValue,oldValue)
});

2)如果需要监听对象类型具体属性的变化,需要设置deep:true,或者使用 “对象.value”。如下:

let goods = ref({name:'',price:0,num:0});
//法一:
watch(goods, (newValue,oldValue)=>{
	console.log("调用了watch:",newValue,oldValue)
},{deep:true});
//法二:
watch(goods.value, (newValue,oldValue)=>{
	console.log("调用了watch:",newValue,oldValue)
};

运行结果:
在这里插入图片描述
3)watch属性可以使用异步。(call一些api)
4) watch在页面初始化加载的时候不会被立刻调用,只有在监听的数据发生变化的时候才会调用。如果想要让他立刻调用可以添加immediate: true

watch(
  source,
  (newValue, oldValue) => {
    // 初始化的时候执行,且当 `source` 改变时再次执行
  },
  { immediate: true }
)
  1. watchEffect
    1)watchEffect资料上说不需要指定具体属性,只要是watchEffect里面使用的数据,都可以进行深层次的监听(可以监听到对象中每个属性的变化)。但是经过测试,发现只会监听使用到的对象的具体的属性,如下图代码,我在watchEffect方法中打印了goods.value和goods.value.name,但只有当我在name输入框中输入数据的时候才会出现打印结果,price,和num输入框都无法触发监听。不知为啥,欢迎交流。
let goods = ref({name:'',price:0,num:0});
watchEffect(()=>{
	console.log("调用了watchEffect",goods.value.name,goods.value)
})

在这里插入图片描述
2) 可以进行异步操作
3)在页面初始化加载的时候会被立刻调用,与watch的immediate类似。

补充:
computed是多对一,一般多个属性变化,会影响到一个属性的时候用computed。computed不可以使用异步。
watch是一对多,一般有一个属性变化,会影响到多个数据的时候使用watch。watch可以使用异步。

<think>我们正在讨论Vue3中的响应式API:watch,computed,watchEffect。根据用户的问题,我们需要解释它们的区别使用场景。同时,根据提供的引用内容,我们可以整合信息。首先,我们整理一下每个API的特点:1.computed:-用于计算属性,基于它们的依赖进行缓存。-必须有返回值。-不支持异步(因为必须返回一个值,而异步操作会导致返回值不可预测)。-适合场景:一个属性受到多个属性影响(如购物车结算)。2.watch:-用于观察一个或多个响应式数据源,并在数据源变化时执行回调函数。-参数:可以指定依赖项(一个或多个)、回调函数、配置选项(如deep,immediate等)。-可以获取变化前的值(oldValue)变化后的值(newValue)。-支持异步操作。-注意:当监视reactive定义的响应式对象时,默认强制深度监视(deep配置失效),但监视其某个属性时deep配置有效。3.watchEffect:-立即执行传入的函数,并在其依赖变更时重新运行该函数。-不需要显式指定依赖项,自动收集函数中使用的响应式依赖。-没有返回值,也无法获取变化前的值,只能得到变化后的值。-提供停止监听的方法(调用其返回的函数)。-支持异步清除副作用(通过onCleanup)。-类似于computed的依赖追踪,但不会缓存结果,而是执行副作用(函数体)。接下来,我们按照使用参数、场景等方面进行对比,并给出使用场景示例。根据引用[4]的总结:-computed:有返回值,不支持异步,适合一个属性受多个属性影响。-watch:可获取先前值当前值,支持异步,可监听多个依赖,可配置。-watchEffect:立即执行,自动收集依赖,不能获取先前值,支持异步清除副作用。我们开始组织回答:</think>### Vue3中`watch`、`computed``watchEffect`的区别与使用场景 #### 1. **核心区别总结** | 特性 | `computed` | `watch` | `watchEffect` | |--------------------|----------------------------|-----------------------------|-----------------------------| | **返回值** | 必须有返回值 | 无返回值 | 无返回值 | | **依赖收集** | 自动收集 | 需显式指定依赖 | 自动收集 | | **执行时机** | 依赖变化时 | 依赖变化时 | **立即执行** + 依赖变化时 | | **获取旧值** | ❌ | ✅ (`oldValue`) | ❌ | | **异步支持** | ❌ | ✅ | ✅ | | **深度监听** | ❌ | 默认浅层(需`deep:true`) | 自动深层监听 | | **停止监听** | ❌ | 调用返回函数 | 调用返回函数 | --- #### 2. **详细解析** ##### (1) **`computed`** - **原理**:基于依赖的**缓存计算**,只有当依赖变化时才重新计算。 - **语法**: ```typescript const value = computed(() => sourceA.value + sourceB.value); // 或带 setter const value = computed({ get: () => source.value, set: (v) => { source.value = v } }); ``` - **场景**: - 需要**返回计算结果**(如购物车总价)。 - 避免重复计算(依赖未变时直接返回缓存值)。 - **限制**: - 不支持异步操作。 - 必须有返回值。 ##### (2) **`watch`** - **原理**:显式监听特定依赖的变化,触发回调。 - **语法**: ```typescript // 监听单个源 watch(source, (newVal, oldVal) => { /*...*/ }, { deep: true }); // 监听多个源 watch([sourceA, sourceB], ([newA, newB], [oldA, oldB]) => { /*...*/ }); ``` - **关键配置**: - `immediate: true`:首次立即执行。 - `deep: true`:深层监听对象(监听`reactive`对象时**默认开启**,此时`deep`配置无效[^3])。 - **场景**: - 需获取**变化前后的值**(如表单修改对比)。 - 执行异步操作(如API请求)。 - 精确控制监听目标(如只监听对象的某个属性)。 ##### (3) **`watchEffect`** - **原理**:**立即执行**回调函数,并自动追踪其内部依赖。 - **语法**: ```typescript const stop = watchEffect((onCleanup) => { // 自动收集依赖 const result = doSomething(source.value); // 清除副作用(如取消请求) onCleanup(() => cancelRequest()); }); // 停止监听 stop(); ``` - **特点**: - 无法获取旧值,只能访问当前值。 - 默认**深层监听**所有依赖。 - 支持**异步副作用清理**(`onCleanup`)。 - **场景**: - 依赖关系复杂(自动收集所有用到的响应式变量)。 - 需要立即执行(如初始化加载数据)。 - 执行副作用操作(如DOM操作、日志记录)。 --- #### 3. **使用场景对比** | 场景 | 推荐 API | 原因 | |--------------------------|----------------|----------------------------------------------------------------------| | **购物车总价计算** | `computed` | 需要缓存计算结果,避免重复计算[^4] | | **表单修改历史记录** | `watch` | 需对比新旧值,且可能异步提交数据[^4] | | **实时搜索(防抖)** | `watch` | 需控制异步请求时序,并获取输入变化 | | **根据路由参数加载数据** | `watchEffect` | 立即执行 + 自动收集`route.params`依赖[^2] | | **监听多层级对象** | `watchEffect` | 避免手动配置`deep:true`(监听`reactive`时`watch`的`deep`会失效[^3]) | | **取消未完成的请求** | `watchEffect` | 通过`onCleanup`清理异步副作用 | --- #### 4. **关键注意事项** 1. **`reactive`对象的监听**: - 用`watch`监听整个`reactive`对象时,**强制开启深度监听**(`deep:true`无效)[^3]。 - 若需监听特定属性,应使用函数返回:`watch(() => obj.key, callback)`。 2. **性能优化**: - `computed`适合计算密集型操作(缓存结果)。 - `watchEffect`的依赖可能过度收集(如条件分支中的变量),需谨慎使用。 3. **组合使用**: ```typescript // 组合 computed + watchEffect const total = computed(() => price.value * quantity.value); watchEffect(() => { if (total.value > 100) showDiscount(); // 自动依赖 total }); ``` --- ### 相关问题 1. **为什么`watch`监听`reactive`对象时`deep`配置会失效?如何精确监听嵌套属性?**[^3] 2. **如何在`watchEffect`中实现异步操作的取消?**(参考`onCleanup`示例) 3. **`computed`的缓存机制如何避免重复计算?在哪些场景下可能失效?** 4. **Vue3中如何手动停止`watch`或`watchEffect`的监听?**(调用返回函数) 5. **在监听多个源时,`watch``watchEffect`的写法有何区别?** [^1]: `watchEffect`的作用类似于`computed`但无返回值,直接执行回调函数。 [^2]: `watchEffect`会立即执行回调,类似`watch`的`{ immediate: true }`配置。 [^3]: 监听`reactive`对象时`deep`配置失效,需用函数返回特定属性;`watchEffect`无法获取旧值。 [^4]: `computed`适合属性联动计算(如购物车),`watch`支持异步旧值获取,`watchEffect`自动收集依赖。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值