Vue3里的computed函数咋用?这些关键知识点你得懂!
computed函数是干啥的?
Vue3里的computed函数,核心是帮咱们处理“基于已有响应式数据,生成新的响应式结果”的场景,比如做购物车时,每个商品有单价和数量,总价得把所有商品的“单价×数量”加起来——这时候用computed,总价就能自动跟着商品的价格、数量变化而更新。
它背后有两个关键逻辑:响应式依赖跟踪和缓存,响应式依赖跟踪指Vue会自动盯着computed里用到的响应式数据(比如ref或reactive定义的变量),一旦这些数据变了,computed的结果就会更新;缓存则更实用——如果依赖的数据没变化,下次用computed结果时,直接拿之前算好的,不用重复计算,省性能。
举个代码例子(用组合式API):
<script setup>
import { ref, computed } from 'vue'
const productPrice = ref(99) // 商品单价(响应式数据)
const productCount = ref(2) // 商品数量(响应式数据)
// 计算总价:单价 × 数量
const totalPrice = computed(() => {
return productPrice.value * productCount.value
})
</script>
这时只要productPrice或productCount变了,totalPrice会自动更新;要是这俩都没变,重复访问totalPrice就直接用缓存的结果,不用再计算。
computed和methods有啥不一样?
很多刚学Vue的同学会纠结:同样写逻辑,为啥不用methods?得从执行时机和性能两方面看明白。
先看methods:methods里的函数,每次页面渲染或者事件触发时都会重新执行,比如写个方法计算总价:
<script setup>
import { ref } from 'vue'
const productPrice = ref(99)
const productCount = ref(2)
function calcTotal() {
return productPrice.value * productCount.value
}
</script>
如果页面里多次调用calcTotal()(比如模板里用了两次{{ calcTotal() }}),每次渲染时这方法会执行多次,但computed是依赖不变就复用结果——不管模板里用多少次,只要productPrice和productCount没变,totalPrice只算一次,之后直接拿缓存。
再从场景区分:methods适合写“触发式”逻辑(比如点击按钮执行一段代码);computed适合“派生式”逻辑(基于已有数据生成新数据,且需要自动更新),简单说,需要自动响应数据变化、且结果能缓存时,选computed;需要主动调用、或逻辑里有副作用(比如发请求、修改DOM),选methods。
computed的缓存机制咋生效?
得先理解Vue的“依赖收集”逻辑:computed内部会跟踪自己用到的响应式数据(比如ref/reactive里的变量),把这些数据当成“依赖”,只有当任意一个依赖发生变化时,computed才会重新计算结果;如果所有依赖都没变,下次访问computed返回的结果时,直接用上次存好的。
举个直观例子:用户全名由firstName和lastName拼接而来:
<script setup>
import { ref, computed } from 'vue'
const firstName = ref('张')
const lastName = ref('三')
const fullName = computed(() => {
console.log('计算全名') // 看执行次数
return firstName.value + lastName.value
})
</script>
第一次访问fullName时,会执行函数、打印“计算全名”,然后缓存结果,之后如果修改firstName,fullName会重新计算(再打印一次);但如果既没改firstName也没改lastName,哪怕多次访问fullName,函数也不会重复执行,直接用缓存——这就是缓存机制的意义:减少不必要的计算,让页面更流畅。
但要注意:如果computed里用了非响应式数据,缓存逻辑会“失效”,比如用普通变量:
let normalVar = '不变的内容'
const wrongComputed = computed(() => {
return normalVar + firstName.value
})
这里normalVar不是响应式的(没被ref/reactive包裹),Vue没法跟踪它的变化,这时候如果normalVar被手动修改了,wrongComputed不会自动更新——因为Vue不知道它依赖了normalVar,所以写computed时,一定要确保依赖的是响应式数据,否则缓存机制就“使不上劲”。
computed能处理复杂逻辑不?比如嵌套依赖、异步?
先看复杂同步逻辑:完全没问题,比如一个页面要根据用户选择的筛选条件过滤商品列表,还要统计符合条件的商品数量,用多个computed嵌套就很丝滑:
<script setup>
import { ref, computed } from 'vue'
const allProducts = ref([/* 商品列表数据 */])
const filterKeyword = ref('') // 筛选关键词
// 第一步:根据关键词过滤商品
const filteredProducts = computed(() => {
return allProducts.value.filter(product =>
product.name.includes(filterKeyword.value)
)
})
// 第二步:统计过滤后的商品数量
const filteredCount = computed(() => {
return filteredProducts.value.length
})
</script>
这里filteredCount依赖filteredProducts,filteredProducts又依赖filterKeyword和allProducts——只要其中任意一个数据变化,整个链条会自动更新,逻辑清晰又省心。
但异步逻辑是computed的短板,因为computed默认期望同步返回结果,如果在computed里写async/await,会导致返回的是Promise,模板里没法直接渲染Promise,这时候得换思路:用watch+computed组合,或者把异步逻辑放async函数里、用ref存结果,再用computed基于这个ref做计算。
举个异步场景的替代方案:
<script setup>
import { ref, watch, computed } from 'vue'
const userId = ref(1) // 用户ID(响应式)
const userInfo = ref(null) // 存用户信息(响应式)
// 异步获取用户信息
watch(userId, async (newId) => {
const res = await fetch(`/api/user/${newId}`)
userInfo.value = await res.json()
})
// 基于userInfo计算用户名(同步逻辑)
const username = computed(() => {
return userInfo.value ? userInfo.value.name : '加载中'
})
</script>
这里watch负责处理异步请求、更新userInfo;computed基于userInfo这个同步的响应式数据做计算——既保留了computed的自动更新和缓存,又处理了异步场景。
写computed时要注意啥?
最容易踩的坑是“在computed里搞副作用”,副作用指“修改其他响应式数据、发请求、操作DOM”这类行为。
const count = ref(0)
const wrongComputed = computed(() => {
count.value++ // 这里修改了count,属于副作用
return count.value * 2
})
这样写会触发循环依赖:computed执行时修改count,而count又是wrongComputed的依赖(因为用到了count.value)——wrongComputed触发count变化,count变化又触发wrongComputed重新计算,无限循环,页面直接卡死,所以记住:computed里只做“纯计算”,返回新结果,别碰其他状态的修改。
第二个注意点是“返回值的确定性”。computed函数必须返回一个值,而且这个值要和依赖的响应式数据关联上,比如别写成这样:
const list = ref([1,2,3])
const wrongComputed = computed(() => {
list.value.push(4) // 没有返回值,或返回undefined
})
模板里如果用{{ wrongComputed }},会渲染undefined,逻辑也不对——computed是用来“计算派生值”,不是用来“修改原数据”的,得确保函数有明确的返回,且返回的是基于依赖计算的结果。
第三个点是“依赖必须是响应式的”,前面提过,如果computed里用了非响应式数据(比如普通变量、props里没被解包的原始值),Vue没法跟踪变化,导致computed不更新,所以写computed前,先确认用到的变量都是ref或reactive包裹的,或者是组件的props(因为props是响应式的)。
Vue3的computed函数是处理“响应式派生数据”的利器,核心优势是自动跟踪依赖+缓存结果,理解它和methods的区别、缓存生效逻辑、复杂场景的处理方式,以及避坑要点,才能在项目里用得顺手——既让代码简洁,又能优化性能~
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
code前端网


