你写的是 setup,还是在 setup 里"试错"?🤨
前言:一句话把 setup 定位清楚(非常重要)
setup 是组件实例创建之前执行的"初始化函数"
它负责:
- 声明响应式状态
- 组合逻辑
- 向模板"暴露能力"
理解了这句话,下面 80% 的坑你都会自动避开。
一、setup 的执行时机:为什么 this 在这里是 undefined?😅
1️⃣ setup 什么时候执行?
Vue 3 组件初始化顺序(简化版)👇
json
创建组件实例
↓
执行 setup()
↓
解析模板 / render
↓
挂载 DOM
↓
mounted
👉 setup 比 beforeCreate / created 还早
2️⃣ 为什么 setup 里没有 this?
因为此时:
- 组件实例 还没完全创建
- data / methods / computed 都不存在
- Vue 直接把你丢进"初始化沙盒"
ts
setup() {
console.log(this) // undefined
}
✅ 正确心态:
在 setup 里,别找 this,找"变量"
二、setup 的参数解析:props 和 context 到底怎么用?
2️⃣ setup 的函数签名
ts
setup(props, context) {}
3️⃣ props:响应式,但"只读"
ts
setup(props) {
console.log(props.title)
}
⚠️ 注意两个重点:
- props 是 响应式的
- props 是 只读的
ts
props.title = 'xxx' // ❌ 会报警告
👉 如果你需要修改:
要么 emit,要么本地复制
4️⃣ 解构 props 的大坑(非常常见)
ts
const { title } = props // ❌ 响应式丢失
✅ 正确写法:
ts
import { toRefs } from 'vue'
const { title } = toRefs(props)
5️⃣ context:被很多人忽略的"工具箱"
ts
setup(props, { emit, slots, attrs, expose }) {}
emit
ts
emit('update', value)
slots
ts
slots.default?.()
attrs
- 非 props 的透传属性
- class / style / id 都在这
expose(高级)
ts
expose({ focus })
👉 控制父组件能通过 ref 访问什么
三、setup 的返回值规则:你"暴露"了什么,模板才能用什么
6️⃣ setup 的返回值 = 模板的作用域
ts
setup() {
const count = ref(0)
return { count }
}
vue
<p>{{ count }}</p>
👉 模板不是全能的,它只能看到你 return 的东西
7️⃣ ref 在模板中为什么不用 .value?
ts
const count = ref(0)
vue
{{ count }} <!-- 自动解包 -->
👉 模板层会自动 unref
👉 JS 里永远记得 .value
8️⃣ return 的"最佳实践"
✅ 推荐返回:
- 响应式状态
- computed
- 方法
- 供模板使用的常量
❌ 不推荐返回:
- 中间变量
- 临时计算结果
- 业务工具函数
四、setup 与模板的关系:这是"绑定",不是"引用"
9️⃣ 模板不是 JS,它是"响应式订阅者"
ts
const count = ref(0)
模板会自动订阅:
- count.value 的变化
- computed 的变化
👉 你不用手动刷新 UI,也不该试图手动刷新
🔟 setup 中声明 ≠ 一定用于模板
ts
const internalCache = new Map()
不 return,它就只是逻辑的一部分。
👉 setup = 逻辑层 + 模板桥梁
五、常见错误示例(⚠️重点,很多人就在这翻车)
❌ 错误 1:在 setup 里使用 this
ts
setup() {
this.fetchData() // ❌
}
✅ 正确:
ts
const fetchData = () => {}
❌ 错误 2:直接解构 props
ts
const { user } = props // ❌
✅ 正确:
ts
const { user } = toRefs(props)
❌ 错误 3:忘了 return,模板用不了
ts
const count = ref(0)
// 模板访问不到
❌ 错误 4:在 setup 里写副作用,但不清理
ts
setInterval(() => {}, 1000) // ❌
✅ 正确:
ts
onMounted(() => {})
onUnmounted(() => {})
❌ 错误 5:setup 写成"第二个 data"
ts
setup() {
const a = ref()
const b = ref()
const c = ref()
// 一坨变量,没有结构
}
✅ 正确思路:
👉 逻辑分组 / 抽成组合式函数
六、setup 的"高级正确打开方式"
1️⃣1️⃣ 把 setup 当成"逻辑拼装区"
ts
setup() {
const user = useUser()
const permission = usePermission()
const pagination = usePagination()
return {
user,
permission,
pagination
}
}
👉 setup 本身应该 很薄
1️⃣2️⃣ <script setup> 的本质(提前说一句)
vue
<script setup>
const count = ref(0)
</script>
等价于:
- 自动 setup
- 自动 return
- 自动 expose 给模板
👉 不是新语法,是编译期糖
七、用一句话给 setup 建立"正确心智模型"
setup = 组件的"启动函数 + 依赖注入 + 能力导出"
不是 data
不是 created
不是万能函数