大家好,我是小杨,一个写了6年前端的Vue钉子户。今天咱们来解决一个永恒的灵魂拷问:computed和watch到底用哪个? 这俩兄弟长得像但脾气完全不同,新手经常用错。看完这篇,保证你从此选得明明白白!
先来个生活化比喻
- computed:就像你的智能助理,你告诉它:"帮我盯着牛奶和咖啡的库存,快没的时候提醒我"。它会自动计算,只在相关库存变化时才通知你。
- watch:就像雇了个私家侦探,你命令他:"24小时盯着我女朋友的微信步数,只要变化就立即报告我!"。不管有没有用,变化一次就报告一次。
代码对比:一看就懂
场景1:显示用户全名
用computed的正确姿势
javascript
data() {
return {
firstName: '张',
lastName: '三'
}
},
computed: {
fullName() {
return `${this.firstName} ${this.lastName}`
}
}
// 模板中直接使用:{{ fullName }}
用watch的错误示范
javascript
data() {
return {
firstName: '张',
lastName: '三',
fullName: ''
}
},
watch: {
firstName(val) {
this.fullName = `${val} ${this.lastName}`
},
lastName(val) {
this.fullName = `${this.firstName} ${val}`
}
}
// 模板中:{{ fullName }}
区别一眼可见:
- computed更简洁,自动追踪依赖
- watch需要手动处理每个依赖项
- computed有缓存,相同值不重复计算
场景2:搜索请求防抖
watch的专属舞台
javascript
data() {
return {
searchQuery: '',
searchResults: []
}
},
watch: {
searchQuery(newVal) {
// 只有在这里才需要手动防抖!
this.debouncedSearch(newVal)
}
},
created() {
this.debouncedSearch = _.debounce(this.doSearch, 500)
},
methods: {
doSearch(query) {
axios.get('/search', { params: { q: query } })
.then(res => this.searchResults = res.data)
}
}
为什么不用computed?
因为这里需要的是副作用(发起请求),而不是计算一个值!
核心区别表格对比
特性 | computed | watch |
---|---|---|
用途 | 计算新值 | 监听变化执行操作 |
缓存 | 有(依赖不变直接返回缓存) | 无(每次变化都执行) |
异步 | 不能 | 可以 |
返回值 | 必须return | 不需要return |
适用场景 | 模板中使用的派生数据 | 数据变化时需要执行副作用操作 |
我踩过的三个大坑
-
在computed里修改data
曾经我这样写:
javascriptcomputed: { userInfo() { this.user.age = 30 // 千万不要这样! return {...this.user} } }
结果导致无限循环更新!computed应该是个纯函数。
-
用watch监听复杂对象
javascriptwatch: { user() { // 对象内部变化不会触发! } }
解决方案:
javascriptwatch: { user: { handler() { /* 处理逻辑 */ }, deep: true // 开启深度监听 } }
-
过度使用watch
新手常犯的错误:
javascript// 错误示范:能用computed偏要用watch watch: { firstName() { /* 更新fullName */ }, lastName() { /* 更新fullName */ } }
这种场景明显应该用computed!
性能优化指南
-
多用computed少用watch
computed有缓存机制,相同值不重复计算。我曾经优化过一个页面,把10个watch改成computed,渲染速度提升了40%!
-
watch的immediate和deep慎用
javascriptwatch: { user: { handler() { /* 逻辑 */ }, deep: true, // 深度监听影响性能 immediate: true // 立即执行可能不需要 } }
-
大对象用computed分拆
javascriptdata() { return { bigData: { /* 超大对象 */ } } }, computed: { importantPart() { return this.bigData.importantPart } }
这样只有importantPart变化才会触发更新
终极选择流程图
plaintext
需要根据其他数据计算新值?
├─ 是 → computed
└─ 否 → 需要在数据变化时执行操作?
├─ 是 → watch
└─ 否 → 可能都不需要!
⭐ 写在最后
请大家不吝赐教,在下方评论或者私信我,十分感谢🙏🙏🙏.
✅ 认为我某个部分的设计过于繁琐,有更加简单或者更高逼格的封装方式
✅ 认为我部分代码过于老旧,可以提供新的API或最新语法
✅ 对于文章中部分内容不理解
✅ 解答我文章中一些疑问
✅ 认为某些交互,功能需要优化,发现BUG
✅ 想要添加新功能,对于整体的设计,外观有更好的建议
✅ 一起探讨技术加qq交流群:906392632
最后感谢各位的耐心观看,既然都到这了,点个 👍赞再走吧!