Vue3 Composition API深度解析与最佳实践前言各位前端小伙伴不知道你们有没有遇到过这种情况Vue2的Options API写复杂组件时代码组织混乱逻辑分散我曾经开发过一个复杂的表单组件使用Options API时data、methods、computed、watch散落在各处维护起来非常痛苦。后来我切换到Composition API代码组织变得清晰多了什么是Composition APIComposition API是Vue3引入的一种新的代码组织方式它允许我们按照功能而非选项类型来组织代码从而更好地复用逻辑。Composition API vs Options APIOptions API的问题// Vue2 Options API export default { data() { return { count: 0, name: Vue } }, methods: { increment() { this.count }, decrement() { this.count-- } }, computed: { doubledCount() { return this.count * 2 } }, watch: { count(newVal) { console.log(Count changed:, newVal) } } }Composition API的优势// Vue3 Composition API import { ref, computed, watch } from vue export default { setup() { const count ref(0) const name ref(Vue) const doubledCount computed(() count.value * 2) function increment() { count.value } function decrement() { count.value-- } watch(count, (newVal) { console.log(Count changed:, newVal) }) return { count, name, doubledCount, increment, decrement } } }Composition API核心概念ref和reactiveimport { ref, reactive } from vue // ref用于基本类型 const count ref(0) console.log(count.value) // 0 count.value console.log(count.value) // 1 // reactive用于对象类型 const state reactive({ name: Vue, version: 3 }) console.log(state.name) // Vue state.version 4 console.log(state.version) // 4computedimport { ref, computed } from vue const firstName ref(John) const lastName ref(Doe) const fullName computed(() { return ${firstName.value} ${lastName.value} }) console.log(fullName.value) // John Doe firstName.value Jane console.log(fullName.value) // Jane Doewatch和watchEffectimport { ref, watch, watchEffect } from vue const count ref(0) // watch需要明确指定依赖 watch(count, (newVal, oldVal) { console.log(Count changed from ${oldVal} to ${newVal}) }) // watchEffect自动追踪依赖 watchEffect(() { console.log(Current count: ${count.value}) })setup函数import { ref, onMounted, onUnmounted } from vue export default { setup() { const width ref(window.innerWidth) function handleResize() { width.value window.innerWidth } onMounted(() { window.addEventListener(resize, handleResize) }) onUnmounted(() { window.removeEventListener(resize, handleResize) }) return { width } } }Composition API实战封装可复用逻辑// useMousePosition.js import { ref, onMounted, onUnmounted } from vue export function useMousePosition() { const x ref(0) const y ref(0) function handleMouseMove(event) { x.value event.clientX y.value event.clientY } onMounted(() { window.addEventListener(mousemove, handleMouseMove) }) onUnmounted(() { window.removeEventListener(mousemove, handleMouseMove) }) return { x, y } } // 在组件中使用 import { useMousePosition } from ./useMousePosition export default { setup() { const { x, y } useMousePosition() return { x, y } } }组合多个逻辑import { useMousePosition } from ./useMousePosition import { useLocalStorage } from ./useLocalStorage export default { setup() { const { x, y } useMousePosition() const { savedPosition, savePosition } useLocalStorage(position) function handleSave() { savePosition({ x: x.value, y: y.value }) } return { x, y, savedPosition, handleSave } } }Composition API高级用法shallowRef和shallowReactiveimport { shallowRef, shallowReactive } from vue // shallowRef只追踪引用变化 const shallow shallowRef({ count: 0 }) shallow.value.count // 不会触发更新 shallow.value { count: 1 } // 会触发更新 // shallowReactive只追踪顶层属性变化 const state shallowReactive({ nested: { count: 0 } }) state.nested.count // 不会触发更新 state.nested { count: 1 } // 会触发更新triggerRefimport { shallowRef, triggerRef } from vue const shallow shallowRef({ count: 0 }) function update() { shallow.value.count triggerRef(shallow) // 手动触发更新 }customRefimport { customRef } from vue function useDebouncedRef(value, delay 300) { let timeout return customRef((track, trigger) { return { get() { track() return value }, set(newValue) { clearTimeout(timeout) timeout setTimeout(() { value newValue trigger() }, delay) } } }) } // 使用 const searchQuery useDebouncedRef()provide和inject// 父组件 import { provide } from vue export default { setup() { const theme ref(dark) provide(theme, theme) return { theme } } } // 子组件 import { inject } from vue export default { setup() { const theme inject(theme) return { theme } } }Composition API最佳实践1. 按功能组织代码// 不好的做法 setup() { const name ref() const email ref() const password ref() const isValid computed(() { return name.value email.value password.value }) function submit() { // 提交逻辑 } return { name, email, password, isValid, submit } } // 好的做法 setup() { const { name, email, password, isValid } useForm() const { submit } useSubmit() return { name, email, password, isValid, submit } }2. 使用ref而非reactive// 不好的做法 const state reactive({ count: 0, name: Vue }) // 好的做法 const count ref(0) const name ref(Vue)3. 避免解构响应式对象// 不好的做法 const state reactive({ count: 0 }) const { count } state // count不再是响应式的 // 好的做法 const state reactive({ count: 0 }) // 直接使用state.count4. 使用computed缓存计算结果// 不好的做法 function getTotal() { return items.value.reduce((sum, item) sum item.price, 0) } // 好的做法 const total computed(() { return items.value.reduce((sum, item) sum item.price, 0) })Composition API常见问题问题1ref需要.value太麻烦解决方案使用reactive替代ref在模板中不需要.value使用toRefs转换import { reactive, toRefs } from vue const state reactive({ count: 0 }) const refs toRefs(state) // refs.count是ref问题2watch不触发解决方案确保依赖是响应式的使用正确的watch语法检查是否使用了shallowRef问题3setup中无法访问this解决方案在setup中不需要this使用ref和reactive代替使用provide/inject传递数据Composition API vs Options API对比特性Options APIComposition API代码组织按选项类型按功能模块逻辑复用MixinsComposablesTypeScript支持有限优秀代码可读性中高学习曲线低中总结Composition API是Vue3最重要的更新之一。通过使用Composition API我们可以更好的代码组织按功能组织代码更好的逻辑复用使用Composables更好的TypeScript支持类型推断更准确更好的性能编译优化现在开始使用Composition API构建更好的Vue应用吧你的同事会感谢你的最后一句忠告不要为了使用Composition API而使用它选择适合你的项目的方式
Vue3 Composition API:深度解析与最佳实践
Vue3 Composition API深度解析与最佳实践前言各位前端小伙伴不知道你们有没有遇到过这种情况Vue2的Options API写复杂组件时代码组织混乱逻辑分散我曾经开发过一个复杂的表单组件使用Options API时data、methods、computed、watch散落在各处维护起来非常痛苦。后来我切换到Composition API代码组织变得清晰多了什么是Composition APIComposition API是Vue3引入的一种新的代码组织方式它允许我们按照功能而非选项类型来组织代码从而更好地复用逻辑。Composition API vs Options APIOptions API的问题// Vue2 Options API export default { data() { return { count: 0, name: Vue } }, methods: { increment() { this.count }, decrement() { this.count-- } }, computed: { doubledCount() { return this.count * 2 } }, watch: { count(newVal) { console.log(Count changed:, newVal) } } }Composition API的优势// Vue3 Composition API import { ref, computed, watch } from vue export default { setup() { const count ref(0) const name ref(Vue) const doubledCount computed(() count.value * 2) function increment() { count.value } function decrement() { count.value-- } watch(count, (newVal) { console.log(Count changed:, newVal) }) return { count, name, doubledCount, increment, decrement } } }Composition API核心概念ref和reactiveimport { ref, reactive } from vue // ref用于基本类型 const count ref(0) console.log(count.value) // 0 count.value console.log(count.value) // 1 // reactive用于对象类型 const state reactive({ name: Vue, version: 3 }) console.log(state.name) // Vue state.version 4 console.log(state.version) // 4computedimport { ref, computed } from vue const firstName ref(John) const lastName ref(Doe) const fullName computed(() { return ${firstName.value} ${lastName.value} }) console.log(fullName.value) // John Doe firstName.value Jane console.log(fullName.value) // Jane Doewatch和watchEffectimport { ref, watch, watchEffect } from vue const count ref(0) // watch需要明确指定依赖 watch(count, (newVal, oldVal) { console.log(Count changed from ${oldVal} to ${newVal}) }) // watchEffect自动追踪依赖 watchEffect(() { console.log(Current count: ${count.value}) })setup函数import { ref, onMounted, onUnmounted } from vue export default { setup() { const width ref(window.innerWidth) function handleResize() { width.value window.innerWidth } onMounted(() { window.addEventListener(resize, handleResize) }) onUnmounted(() { window.removeEventListener(resize, handleResize) }) return { width } } }Composition API实战封装可复用逻辑// useMousePosition.js import { ref, onMounted, onUnmounted } from vue export function useMousePosition() { const x ref(0) const y ref(0) function handleMouseMove(event) { x.value event.clientX y.value event.clientY } onMounted(() { window.addEventListener(mousemove, handleMouseMove) }) onUnmounted(() { window.removeEventListener(mousemove, handleMouseMove) }) return { x, y } } // 在组件中使用 import { useMousePosition } from ./useMousePosition export default { setup() { const { x, y } useMousePosition() return { x, y } } }组合多个逻辑import { useMousePosition } from ./useMousePosition import { useLocalStorage } from ./useLocalStorage export default { setup() { const { x, y } useMousePosition() const { savedPosition, savePosition } useLocalStorage(position) function handleSave() { savePosition({ x: x.value, y: y.value }) } return { x, y, savedPosition, handleSave } } }Composition API高级用法shallowRef和shallowReactiveimport { shallowRef, shallowReactive } from vue // shallowRef只追踪引用变化 const shallow shallowRef({ count: 0 }) shallow.value.count // 不会触发更新 shallow.value { count: 1 } // 会触发更新 // shallowReactive只追踪顶层属性变化 const state shallowReactive({ nested: { count: 0 } }) state.nested.count // 不会触发更新 state.nested { count: 1 } // 会触发更新triggerRefimport { shallowRef, triggerRef } from vue const shallow shallowRef({ count: 0 }) function update() { shallow.value.count triggerRef(shallow) // 手动触发更新 }customRefimport { customRef } from vue function useDebouncedRef(value, delay 300) { let timeout return customRef((track, trigger) { return { get() { track() return value }, set(newValue) { clearTimeout(timeout) timeout setTimeout(() { value newValue trigger() }, delay) } } }) } // 使用 const searchQuery useDebouncedRef()provide和inject// 父组件 import { provide } from vue export default { setup() { const theme ref(dark) provide(theme, theme) return { theme } } } // 子组件 import { inject } from vue export default { setup() { const theme inject(theme) return { theme } } }Composition API最佳实践1. 按功能组织代码// 不好的做法 setup() { const name ref() const email ref() const password ref() const isValid computed(() { return name.value email.value password.value }) function submit() { // 提交逻辑 } return { name, email, password, isValid, submit } } // 好的做法 setup() { const { name, email, password, isValid } useForm() const { submit } useSubmit() return { name, email, password, isValid, submit } }2. 使用ref而非reactive// 不好的做法 const state reactive({ count: 0, name: Vue }) // 好的做法 const count ref(0) const name ref(Vue)3. 避免解构响应式对象// 不好的做法 const state reactive({ count: 0 }) const { count } state // count不再是响应式的 // 好的做法 const state reactive({ count: 0 }) // 直接使用state.count4. 使用computed缓存计算结果// 不好的做法 function getTotal() { return items.value.reduce((sum, item) sum item.price, 0) } // 好的做法 const total computed(() { return items.value.reduce((sum, item) sum item.price, 0) })Composition API常见问题问题1ref需要.value太麻烦解决方案使用reactive替代ref在模板中不需要.value使用toRefs转换import { reactive, toRefs } from vue const state reactive({ count: 0 }) const refs toRefs(state) // refs.count是ref问题2watch不触发解决方案确保依赖是响应式的使用正确的watch语法检查是否使用了shallowRef问题3setup中无法访问this解决方案在setup中不需要this使用ref和reactive代替使用provide/inject传递数据Composition API vs Options API对比特性Options APIComposition API代码组织按选项类型按功能模块逻辑复用MixinsComposablesTypeScript支持有限优秀代码可读性中高学习曲线低中总结Composition API是Vue3最重要的更新之一。通过使用Composition API我们可以更好的代码组织按功能组织代码更好的逻辑复用使用Composables更好的TypeScript支持类型推断更准确更好的性能编译优化现在开始使用Composition API构建更好的Vue应用吧你的同事会感谢你的最后一句忠告不要为了使用Composition API而使用它选择适合你的项目的方式