90%的Vue3项目都在用 <script setup>,代码少、效率高。
但很多人只懂语法不懂原理,日常开发疯狂踩坑:数据不更新、弹窗缓存错乱、watch死循环、页面越用越卡。
这些bug不是逻辑写错了,而是 script setup 的隐性规则没吃透!
今天总结5个最高频的坑,附错误案例+正确写法,看完直接避坑。
01 | 变量直接赋值,丢失响应式
新手排查最久的坑。以为 let 定义就是响应式,结果数据变了页面纹丝不动。
❌ 错误写法
// 普通变量,Vue无法监听
let count = 0
const add = () => count++ ✅ 正确写法
import { ref } from 'vue'
// 基础类型必须用ref包裹
const count = ref(0)
const add = () => count.value++💡 避坑口诀:基础类型用
ref,对象数组用reactive,别信裸变量。
02 | watch全量监听,触发无限死循环
图省事直接监听整个对象还开 deep,内部修改属性瞬间触发递归更新,CPU飙升页面卡死。
❌ 致命写法
watch(form, () => {
form.age++ // 修改自身 → 再次触发watch → 死循环💥
}, { deep: true })✅ 安全写法
// 精准监听具体字段,按需开启deep
watch(() => form.age, (val) => {
console.log('年龄变化:', val)
})💡 避坑口诀:监听要精准,拒绝无脑
deep,杜绝自我触发。
03 | 弹窗关闭再打开,脏数据残留
后台项目100%遇到的bug:编辑弹窗关了再开,上次的表单值、校验报错还在。
根源:<script setup> 组件实例会缓存状态,仅隐藏不会重置。
❌ 错误做法
只用 v-model 控制显隐,数据永远保留旧值。
✅ 终极方案(二选一)
<!-- 方案1:v-if 强制销毁重建(推荐) -->
<el-dialog v-if="visible" />
<!-- 方案2:打开时手动重置 -->
const open = () => {
Object.assign(form, defaultForm)
ruleFormRef.value?.clearValidate()
visible.value = true
}💡 避坑口诀:弹窗状态错乱?
v-if销毁重建最省心。
04 | 解构reactive,响应式直接断裂
为了代码简洁解构对象,结果双向绑定当场失效,改数据页面无反应。
❌ 错误写法
const user = reactive({ name: '张三' })
// 解构后变成普通值,失去响应式
const { name } = user ✅ 正确写法
import { toRefs } from 'vue'
const user = reactive({ name: '张三' })
// toRefs 保留每个属性的响应式引用
const { name } = toRefs(user)💡 避坑口诀:
reactive解构必加toRefs,否则绑定全白费。
05 | 模板内写匿名函数,内存泄漏卡顿
在 v-for 里滥用箭头函数,每次渲染都生成新函数引用,导致子组件无效重渲染,页面越滚越卡。
❌ 低效写法
<div @click="() => handleClick(item)">
{{ item.name }}
</div>✅ 高效写法
<!-- 统一封装,避免重复创建函数 -->
<div @click="handleClick(item)">
{{ item.name }}
</div>💡 避坑口诀:模板拒绝匿名函数,方法统一提取,性能拉满。