Code前端首页关于Code前端联系我们

Vue3里的computed函数咋用?这些关键知识点你得懂!

terry 2小时前 阅读数 19 #SEO
文章标签 Vue3;computed

computed函数是干啥的?

Vue3里的computed函数,核心是帮咱们处理“基于已有响应式数据,生成新的响应式结果”的场景,比如做购物车时,每个商品有单价和数量,总价得把所有商品的“单价×数量”加起来——这时候用computed,总价就能自动跟着商品的价格、数量变化而更新。

它背后有两个关键逻辑:响应式依赖跟踪缓存,响应式依赖跟踪指Vue会自动盯着computed里用到的响应式数据(比如refreactive定义的变量),一旦这些数据变了,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>

这时只要productPriceproductCount变了,totalPrice会自动更新;要是这俩都没变,重复访问totalPrice就直接用缓存的结果,不用再计算。

computed和methods有啥不一样?

很多刚学Vue的同学会纠结:同样写逻辑,为啥不用methods?得从执行时机性能两方面看明白。

先看methodsmethods里的函数,每次页面渲染或者事件触发时都会重新执行,比如写个方法计算总价:

<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依赖不变就复用结果——不管模板里用多少次,只要productPriceproductCount没变,totalPrice只算一次,之后直接拿缓存。

再从场景区分:methods适合写“触发式”逻辑(比如点击按钮执行一段代码);computed适合“派生式”逻辑(基于已有数据生成新数据,且需要自动更新),简单说,需要自动响应数据变化、且结果能缓存时,选computed;需要主动调用、或逻辑里有副作用(比如发请求、修改DOM),选methods

computed的缓存机制咋生效?

得先理解Vue的“依赖收集”逻辑:computed内部会跟踪自己用到的响应式数据(比如ref/reactive里的变量),把这些数据当成“依赖”,只有当任意一个依赖发生变化时,computed才会重新计算结果;如果所有依赖都没变,下次访问computed返回的结果时,直接用上次存好的。

举个直观例子:用户全名由firstNamelastName拼接而来:

<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时,会执行函数、打印“计算全名”,然后缓存结果,之后如果修改firstNamefullName会重新计算(再打印一次);但如果既没改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依赖filteredProductsfilteredProducts又依赖filterKeywordallProducts——只要其中任意一个数据变化,整个链条会自动更新,逻辑清晰又省心。

异步逻辑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负责处理异步请求、更新userInfocomputed基于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前,先确认用到的变量都是refreactive包裹的,或者是组件的props(因为props是响应式的)。

Vue3的computed函数是处理“响应式派生数据”的利器,核心优势是自动跟踪依赖+缓存结果,理解它和methods的区别、缓存生效逻辑、复杂场景的处理方式,以及避坑要点,才能在项目里用得顺手——既让代码简洁,又能优化性能~

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

热门