大白话 Vue 3 Composition API 中 setup 函数的执行时机和参数是什么?与 Vue 2 的 beforeCreate/created 钩子有何区别?
前端小伙伴们,有没有被Vue3的setup函数搞得晕头转向?它到底什么时候执行?和Vue2的beforeCreate/created钩子有啥区别?今天就用大白话给你讲清楚,包你3分钟搞懂,面试再也不怕被问啦!
一、Vue2生命周期的尴尬
场景一:代码逻辑分散
在Vue2里,相关的逻辑可能分散在不同的生命周期钩子中,比如数据获取和状态初始化可能分别在created和mounted里,代码可读性差。
场景二:复杂组件难以维护
对于复杂组件,各种逻辑混合在多个钩子中,导致代码难以理解和维护。
场景三:逻辑复用困难
Vue2的mixins存在命名冲突和来源不明确等问题,导致逻辑复用困难。
二、setup函数的执行时机和参数
1. 执行时机
setup函数是Vue3 Composition API的入口点,它在组件实例初始化之后,beforeCreate
钩子之前执行。这意味着在setup函数中,组件实例还没有完全创建,所以无法访问this
。
2. 参数
setup函数接收两个参数:
- props:组件的props对象,是响应式的。
- context:上下文对象,包含attrs、slots和emit等属性。
3. 与Vue2生命周期的关系
Vue 2 钩子 | Vue 3 等效位置 |
---|---|
beforeCreate | setup函数开始 |
created | setup函数中(同步部分) |
beforeMount | onBeforeMount |
mounted | onMounted |
beforeUpdate | onBeforeUpdate |
updated | onUpdated |
beforeDestroy | onBeforeUnmount |
destroyed | onUnmounted |
errorCaptured | onErrorCaptured |
三、代码示例:setup函数的使用
示例一:基本使用
import { ref, onMounted } from 'vue'
export default {
props: {
msg: String
},
setup(props, context) {
// 访问props
console.log(props.msg) // 可以直接访问props
// 创建响应式数据
const count = ref(0)
// 定义方法
const increment = () => {
count.value++
}
// 生命周期钩子等效
onMounted(() => {
console.log('组件已挂载')
})
// 返回模板中需要使用的数据和方法
return {
count,
increment
}
}
}
示例二:使用context参数
import { ref } from 'vue'
export default {
setup(props, context) {
// context包含attrs、slots和emit等属性
// attrs:非props的属性
console.log(context.attrs)
// slots:访问插槽内容
console.log(context.slots)
// emit:触发自定义事件
const handleClick = () => {
context.emit('custom-event', 'hello')
}
return {
handleClick
}
}
}
示例三:与Vue2生命周期对比
// Vue 2 组件
export default {
data() {
return {
count: 0
}
},
props: {
msg: String
},
beforeCreate() {
console.log('beforeCreate')
// 此时data和props都还没初始化
},
created() {
console.log('created')
// 此时data和props已初始化
// 可以访问this.count和this.msg
},
mounted() {
console.log('mounted')
}
}
// Vue 3 等效组件
import { ref, onMounted } from 'vue'
export default {
props: {
msg: String
},
setup(props) {
console.log('setup开始')
// 相当于beforeCreate位置
// 此时props已可用,但不能访问this
const count = ref(0)
// 相当于created位置的data初始化
onMounted(() => {
console.log('mounted')
})
return {
count
}
}
}
四、setup函数与Vue2生命钩子对比
对比项 | Vue 2 beforeCreate/created | Vue 3 setup函数 |
---|---|---|
执行时机 | 组件实例初始化后 | 组件实例初始化后,beforeCreate之前 |
this访问 | 可以访问this(有限制) | 无法访问this |
props访问 | 通过this.props访问 | 直接作为参数props访问 |
数据定义 | 在data函数中定义 | 使用ref或reactive定义 |
逻辑组织 | 分散在多个钩子中 | 可以集中组织相关逻辑 |
逻辑复用 | 依赖mixins(有命名冲突问题) | 可以使用组合函数复用 |
五、面试回答方法
面试时被问到setup函数的执行时机和参数,可以这样回答:
“面试官您好!Vue3的setup函数是Composition API的入口点,它的执行时机和参数可以这样理解:
-
执行时机:setup函数在组件实例初始化之后,beforeCreate钩子之前执行。这时候组件实例还没完全创建好,所以在setup里访问不了this。
-
参数:setup函数接收两个参数:
- props:就是组件的props对象,它是响应式的,当props变化时会自动更新。
- context:这是个上下文对象,里面有attrs(非props属性)、slots(插槽内容)和emit(触发自定义事件)等实用的东西。
-
与Vue2的区别:
- setup函数替代了Vue2的beforeCreate和created钩子。
- 在setup里不能用this,要获取props和触发事件得通过参数。
- setup可以更好地组织相关逻辑,解决了Vue2里逻辑分散的问题。
举个例子,在setup里我们可以用ref或reactive创建响应式数据,定义方法,还能通过onMounted等函数来实现和Vue2生命周期钩子类似的功能。”
六、总结:核心要点回顾
- 执行时机:在组件实例初始化后,beforeCreate之前执行。
- 参数:props(响应式)和context(包含attrs、slots、emit)。
- 无法访问this:setup函数中没有this,需要通过参数访问props和触发事件。
- 替代Vue2钩子:基本替代了Vue2的beforeCreate和created钩子。
- 逻辑组织:可以将相关逻辑集中在一起,提高代码可读性和可维护性。
七、扩展思考
问题1:setup函数中可以使用异步操作吗?
可以使用异步操作,但要注意setup函数如果返回Promise,模板将无法访问返回的数据。如果需要异步获取数据,可以在setup中使用ref或reactive定义数据,然后在异步操作完成后更新这些数据。
问题2:setup函数中的props是响应式的吗?
是的,setup函数中的props是响应式的,当父组件传递的props发生变化时,setup函数中的props也会相应更新。但要注意,不能直接修改props,这会导致Vue发出警告。
问题3:setup函数可以返回什么?
setup函数可以返回一个对象,对象中的属性和方法可以在模板中使用。此外,setup函数还可以返回一个渲染函数,用于手动渲染组件。
问题4:setup函数中的生命周期钩子是如何工作的?
在setup函数中,可以通过导入onMounted、onUpdated等函数来使用生命周期钩子。这些函数接收一个回调函数,回调函数会在对应的生命周期阶段执行。例如,onMounted的回调会在组件挂载后执行。
问题5:setup函数与Vue3的组合式函数(Composables)有什么关系?
setup函数是使用组合式函数的核心场所。组合式函数是将可复用的逻辑提取出来的函数,比如提取一个处理数据请求和状态管理的逻辑。在setup函数中,可以直接调用这些组合式函数,实现逻辑的复用和拆分。
例如,我们创建一个名为useFetchData
的组合式函数:
import { ref, onMounted } from 'vue';
// 组合式函数:处理数据请求和状态管理
export function useFetchData(url) {
const data = ref(null);
const isLoading = ref(true);
const error = ref(null);
const fetchData = async () => {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
data.value = await response.json();
} catch (err) {
error.value = err;
} finally {
isLoading.value = false;
}
};
onMounted(() => {
fetchData();
});
return {
data,
isLoading,
error
};
}
然后在组件的setup函数中使用:
import { useFetchData } from './composables';
export default {
setup() {
// 使用组合式函数
const { data, isLoading, error } = useFetchData('https://api.example.com/data');
return {
data,
isLoading,
error
};
}
};
通过这种方式,setup函数成为了组合式函数的“舞台”,将各个独立的逻辑片段组合成完整的组件功能,大大提高了代码的复用性和可维护性 。
问题6:setup函数在服务端渲染(SSR)中有什么特殊考虑?
在SSR环境下,setup函数的执行和浏览器环境有所不同。由于服务端没有真实的DOM,一些依赖浏览器环境的操作(如访问window对象)需要进行特殊处理。
例如,在setup函数中如果需要根据浏览器窗口大小设置响应式数据,就需要判断当前环境是否为服务端:
import { ref, onMounted } from 'vue';
export default {
setup() {
const windowWidth = ref(0);
const setWindowWidth = () => {
if (typeof window!== 'undefined') {
windowWidth.value = window.innerWidth;
}
};
onMounted(() => {
window.addEventListener('resize', setWindowWidth);
setWindowWidth();
});
return {
windowWidth
};
}
};
此外,在SSR中还要注意setup函数中异步操作的处理,确保数据在渲染前已经准备好,避免出现数据未定义的情况。同时,组件的状态管理也需要在服务端和客户端之间进行正确的传递和同步 。
问题7:setup函数如何影响组件的性能?
合理使用setup函数可以提升组件性能。因为setup函数可以将相关逻辑集中在一起,减少不必要的计算和渲染。比如,通过组合式函数将数据获取和处理逻辑复用,避免在多个组件中重复编写相似代码,从而减少打包体积和执行时间。
但如果使用不当,也可能影响性能。例如,在setup函数中创建过多不必要的响应式数据,或者频繁地更新响应式数据,可能会导致不必要的重新渲染。此外,如果在setup函数中执行大量复杂的计算,也会影响组件的初始化速度。因此,在使用setup函数时,需要根据实际需求,合理组织逻辑和管理响应式数据,以达到性能优化的目的 。
问题8:setup函数与Vue3的响应式API(ref/reactive)是如何配合工作的?
setup函数是使用Vue3响应式API的主要场所。ref用于创建一个响应式的引用,它可以包裹基本数据类型和对象;reactive则用于将一个普通对象转换为响应式对象。
在setup函数中,我们可以使用ref创建响应式的基本数据:
import { ref } from 'vue';
export default {
setup() {
const count = ref(0);
const increment = () => {
count.value++;
};
return {
count,
increment
};
}
};
也可以使用reactive创建响应式的对象:
import { reactive } from 'vue';
export default {
setup() {
const user = reactive({
name: '张三',
age: 20
});
const updateName = () => {
user.name = '李四';
};
return {
user,
updateName
};
}
};
当响应式数据发生变化时,Vue会自动检测到变化,并更新相关的DOM。setup函数提供了一个统一的地方来管理这些响应式数据和相关的操作逻辑,使得组件的状态管理更加清晰和直观 。
通过对这些扩展问题的探讨,相信大家对Vue3的setup函数有了更深入、全面的理解。从执行机制到实际应用,从性能优化到与其他API的配合,setup函数在Vue3的开发中扮演着举足轻重的角色。在实际项目里,多运用这些知识,不断积累经验,就能写出更高效、更易维护的代码。要是你在学习或实践过程中还有疑问,或者遇到了新的问题,欢迎在评论区留言交流,咱们一起把Vue3玩得明明白白!