用了这么久Vue,你真的懂Computed和Watch的区别吗?

你是不是经常在写Vue时纠结:这个功能到底该用computed还是watch?明明两个都能实现,但用哪个更合适?

有时候选了watch,代码变得又长又难维护;有时候用了computed,却发现根本监听不到数据变化。别急,今天我就带你彻底搞懂这两个家伙,让你的代码既优雅又高效!

先来认识一下这三位"候选人"

在Vue的世界里,处理数据变化主要有三种方式:计算属性(computed)、方法(methods)和侦听器(watch)。它们各自有不同的"职责范围"。

计算属性就像个聪明的助手,它会根据依赖的数据自动计算出一个新值,而且还会缓存结果,只有依赖变了才会重新计算。

方法就是个老实人,你叫它一次它就干一次活,不管数据变没变。

侦听器则像个保安,专门盯着某个数据的变化,一旦有动静就立即执行你交代的任务。

听起来有点抽象?来看个实际例子你就明白了:

// 计算属性的用法
computed: {
  fullName() {
    return this.firstName + ' ' + this.lastName
  }
}

// 方法的用法  
methods: {
  getFullName() {
    return this.firstName + ' ' + this.lastName
  }
}

// 侦听器的用法
watch: {
  firstName(newVal) {
    this.fullName = newVal + ' ' + this.lastName
  },
  lastName(newVal) {
    this.fullName = this.firstName + ' ' + newVal
  }
}

看到区别了吗?计算属性只需要一个函数就搞定了全名,而侦听器需要分别监听姓和名的变化,代码量多了不少。

什么时候该用谁?

记住这个选择原则:能用computed就尽量用computed,需要异步或执行副作用时用watch

计算属性的最佳使用场景

计算属性特别适合这两种情况:

  1. 模板中的复杂表达式:当模板中有太多逻辑时,应该用计算属性来简化
// 不好的写法:模板里写太多逻辑
<template>
  <div>{{ message.split('').reverse().join('') }}</div>
</template>

// 好的写法:用计算属性
<template>
  <div>{{ reversedMessage }}</div>
</template>

<script>
export default {
  computed: {
    reversedMessage() {
      return this.message.split('').reverse().join('')
    }
  }
}
</script>
  1. 依赖多个数据源的计算:当一个值需要根据多个数据来计算时
computed: {
  // 购物车总价,依赖商品列表和每种商品的数量
  totalPrice() {
    return this.products.reduce((total, product) => {
      return total + product.price * product.quantity
    }, 0)
  }
}

侦听器的正确打开方式

watch通常在以下情况使用:

  1. 数据变化时需要执行异步操作
  2. 数据变化时需要执行副作用(如调用API)
  3. 需要监听路由变化等非响应式数据
watch: {
  // 搜索关键词变化时,延迟500毫秒后搜索
  searchKeyword(newVal) {
    if (this.timer) {
      clearTimeout(this.timer)
    }
    this.timer = setTimeout(() => {
      this.doSearch(newVal)
    }, 500)
  }
}

那些年我们踩过的watch坑

watch虽然强大,但用不好就会掉坑里。最常见的就是深度监听和立即执行的问题。

deep选项:监听对象内部变化

默认情况下,watch只监听对象本身的赋值变化,不监听对象内部属性的变化。这时候就需要deep选项出场了。

data() {
  return {
    user: {
      name: '张三',
      address: {
        city: '北京'
      }
    }
  }
},
watch: {
  // 普通监听:只有整个user对象被重新赋值时才会触发
  user(newVal) {
    console.log('用户信息变了')
  },
  
  // 深度监听:user内部的任何属性变化都会触发
  user: {
    handler(newVal) {
      console.log('用户信息深度变化')
    },
    deep: true  // 开启深度监听
  }
}

但要注意:深度监听性能开销较大,尽量不要对大对象使用。

immediate选项:初始立即执行

有时候我们希望watch在组件创建时就立即执行一次,这时候就需要immediate选项。

watch: {
  // 默认不会立即执行
  someData(newVal) {
    console.log('数据变化了')
  },
  
  // 设置immediate: true后会立即执行一次
  someData: {
    handler(newVal) {
      console.log('数据变化或初始执行')
    },
    immediate: true
  }
}

Vue 3中的watch和watchEffect

如果你已经开始用Vue 3,那么watch的用法有了一些新变化,还多了一个watchEffect。

watch的Composition API用法

import { ref, watch } from 'vue'

export default {
  setup() {
    const count = ref(0)
    const doubleCount = ref(0)
    
    // 监听count的变化
    watch(count, (newVal, oldVal) => {
      doubleCount.value = newVal * 2
    })
    
    return { count, doubleCount }
  }
}

watchEffect:自动追踪依赖

watchEffect是Vue 3的新特性,它会自动追踪函数内使用的响应式数据,任何被使用的数据发生变化都会触发回调。

import { ref, watchEffect } from 'vue'

export default {
  setup() {
    const count = ref(0)
    const doubleCount = ref(0)
    
    // 自动追踪count,count变化就执行
    watchEffect(() => {
      doubleCount.value = count.value * 2
    })
    
    return { count, doubleCount }
  }
}

watch和watchEffect的主要区别是:watch需要明确指定监听的数据,而watchEffect会自动收集依赖。

实战避坑指南

说了这么多理论,来看几个实际开发中容易踩的坑:

坑1:在watch中修改监听的数据

这会导致无限循环,要特别小心!

// 错误示范:会导致无限循环
watch: {
  count(newVal) {
    this.count = newVal + 1  // 修改监听的数据,又会触发watch...
  }
}

// 正确做法:添加条件判断
watch: {
  count(newVal) {
    if (newVal < 10) {
      this.count = newVal + 1
    }
  }
}

坑2:忘记处理异步操作的竞态条件

当连续触发多次异步操作时,需要确保最终结果是正确的。

watch: {
  async searchQuery(newVal) {
    // 取消之前的请求
    if (this.currentRequest) {
      this.currentRequest.cancel()
    }
    
    // 发起新请求
    this.currentRequest = this.$http.get('/search', { params: { q: newVal } })
    this.results = await this.currentRequest
  }
}

总结一下

说了这么多,我们来个简单总结:

  • computed:用于派生数据,有缓存,依赖变化才重新计算
  • methods:用于事件处理或需要主动调用的函数
  • watch:用于数据变化时需要执行副作用或异步操作的场景

记住这个选择口诀:想要派生新数据,computed是第一选择;想要响应数据变,watch来帮你搞定;需要主动调用的,methods才是正解

现在你已经掌握了computed和watch的正确打开方式,下次写代码时就不会再纠结了吧?

你在使用computed和watch时还遇到过哪些坑?欢迎在评论区分享你的经历和解决方案!

原文链接:https://mp.weixin.qq.com/s/8-jMcOGNTIe-1sI0VaTUag

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值