组合式API的设计哲学
组合式API的设计哲学
组合式API是Vue3中最重要的创新之一,它彻底改变了Vue组件的组织方式。这种API风格允许开发者将相关逻辑组织在一起,而不是按照选项API的生命周期或功能类型强制分离代码。
逻辑关注点分离
传统选项API强制按照功能类型分离代码,导致同一业务逻辑分散在不同选项中。组合式API通过setup()
函数解决了这个问题:
// 选项API的问题:相关逻辑分散
export default {
data() {
return {
count: 0,
double: 0
}
},
watch: {
count(newVal) {
this.double = newVal * 2
}
},
methods: {
increment() {
this.count++
}
}
}
// 组合式API解决方案
import { ref, watch } from 'vue'
export default {
setup() {
const count = ref(0)
const double = ref(0)
watch(count, (newVal) => {
double.value = newVal * 2
})
function increment() {
count.value++
}
return { count, double, increment }
}
}
更好的类型推断
组合式API天然对TypeScript更友好,因为它的返回值类型可以明确声明:
import { ref } from 'vue'
export default {
setup() {
const count = ref<number>(0) // 明确类型
return {
count,
increment: () => count.value++ // 自动推断返回类型
}
}
}
逻辑复用能力
组合式API通过组合函数实现了真正的逻辑复用,这是mixin和HOC难以达到的:
// 复用逻辑的封装
function useCounter(initialValue = 0) {
const count = ref(initialValue)
function increment() {
count.value++
}
return {
count,
increment
}
}
// 在组件中使用
export default {
setup() {
const { count, increment } = useCounter()
return {
count,
increment
}
}
}
响应式系统的核心
组合式API深度集成了Vue3的响应式系统,ref
和reactive
是其基础:
import { ref, reactive, computed } from 'vue'
export default {
setup() {
const state = reactive({
firstName: '张',
lastName: '三'
})
const fullName = computed(() => `${state.firstName}${state.lastName}`)
const age = ref(30)
return {
state,
fullName,
age
}
}
}
生命周期钩子的整合
组合式API将生命周期钩子统一为函数形式,可以更灵活地组织:
import { onMounted, onUpdated } from 'vue'
export default {
setup() {
onMounted(() => {
console.log('组件挂载')
})
onUpdated(() => {
console.log('组件更新')
})
// 可以多次调用同一个生命周期
onMounted(() => {
console.log('另一个挂载逻辑')
})
}
}
与选项API的互操作性
组合式API可以与选项API共存,便于渐进式迁移:
export default {
setup() {
const count = ref(0)
return { count }
},
mounted() {
console.log('传统选项API生命周期')
},
methods: {
traditionalMethod() {
console.log('传统方法')
}
}
}
性能优化潜力
组合式API为编译器优化提供了更多可能性,比如更精确的依赖跟踪:
import { computed } from 'vue'
export default {
setup() {
const state = reactive({
a: 1,
b: 2,
c: 3
})
// 只有state.a变化时才会重新计算
const computedA = computed(() => state.a * 2)
return {
computedA
}
}
}
更好的代码组织模式
组合式API鼓励将复杂逻辑拆分为多个组合函数:
function useUser() {
const user = ref(null)
// 用户相关逻辑...
return { user }
}
function usePosts() {
const posts = ref([])
// 文章相关逻辑...
return { posts }
}
export default {
setup() {
const { user } = useUser()
const { posts } = usePosts()
return {
user,
posts
}
}
}
与渲染上下文的解耦
组合式API可以在组件外部使用,这为测试和复用提供了便利:
// 在组件外部定义逻辑
function useFeature() {
const value = ref(0)
// 逻辑代码...
return { value }
}
// 测试时可以直接调用
test('useFeature', () => {
const { value } = useFeature()
// 测试逻辑...
})
// 在组件中使用
export default {
setup() {
return useFeature()
}
}
响应式工具函数的丰富
组合式API提供了一系列响应式工具函数,增强了开发体验:
import { toRefs, isRef, unref } from 'vue'
export default {
setup() {
const state = reactive({
foo: 1,
bar: 2
})
// 解构保持响应性
const { foo, bar } = toRefs(state)
// 检查是否是ref
console.log(isRef(foo)) // true
// 安全获取值
const value = unref(maybeRef)
return {
foo,
bar
}
}
}
与模板的深度集成
组合式API返回的值可以直接在模板中使用,保持了一致的开发体验:
<template>
<div>
<p>{{ count }}</p>
<button @click="increment">+1</button>
</div>
</template>
<script>
import { ref } from 'vue'
export default {
setup() {
const count = ref(0)
function increment() {
count.value++
}
return {
count,
increment
}
}
}
</script>
响应式状态管理
组合式API简化了状态管理,可以轻松创建可复用的store:
// store.js
import { reactive } from 'vue'
export const store = reactive({
count: 0,
increment() {
this.count++
}
})
// 组件中使用
import { store } from './store'
export default {
setup() {
return {
store
}
}
}
异步逻辑处理
组合式API提供了更优雅的异步处理方式:
import { ref } from 'vue'
import { fetchUser } from './api'
export default {
async setup() {
const user = ref(null)
const loading = ref(false)
loading.value = true
user.value = await fetchUser()
loading.value = false
return {
user,
loading
}
}
}
依赖注入系统
组合式API改进了依赖注入机制,使其更类型安全:
import { provide, inject } from 'vue'
// 提供者组件
export default {
setup() {
provide('theme', 'dark')
}
}
// 消费者组件
export default {
setup() {
const theme = inject<string>('theme', 'light') // 默认值'light'
return { theme }
}
}
自定义hook的兴起
组合式API催生了丰富的自定义hook生态系统:
// useMousePosition.js
import { ref, onMounted, onUnmounted } from 'vue'
export function useMousePosition() {
const x = ref(0)
const y = ref(0)
function update(e) {
x.value = e.pageX
y.value = e.pageY
}
onMounted(() => window.addEventListener('mousemove', update))
onUnmounted(() => window.removeEventListener('mousemove', update))
return { x, y }
}
// 组件中使用
export default {
setup() {
const { x, y } = useMousePosition()
return { x, y }
}
}
响应式编程范式
组合式API鼓励采用更声明式的编程风格:
import { ref, watchEffect } from 'vue'
export default {
setup() {
const count = ref(0)
// 自动追踪依赖
watchEffect(() => {
console.log(`count is: ${count.value}`)
})
return {
count
}
}
}
与JSX的协同
组合式API与JSX结合使用时表现出色:
import { defineComponent, ref } from 'vue'
export default defineComponent({
setup() {
const count = ref(0)
return () => (
<div>
<button onClick={() => count.value++}>
Count is: {count.value}
</button>
</div>
)
}
})
编译时优化支持
组合式API为Vue3的编译器优化奠定了基础:
import { ref } from 'vue'
export default {
setup() {
// 编译器可以静态分析这些引用
const count = ref(0)
const double = computed(() => count.value * 2)
return {
count,
double
}
}
}
跨组件通信模式
组合式API提供了新的跨组件通信方式:
// 父组件
import { provide, ref } from 'vue'
export default {
setup() {
const sharedState = ref('initial value')
provide('shared-key', sharedState)
}
}
// 子组件
import { inject } from 'vue'
export default {
setup() {
const sharedState = inject('shared-key')
return { sharedState }
}
}
响应式集合操作
组合式API简化了集合操作:
import { reactive } from 'vue'
export default {
setup() {
const list = reactive([1, 2, 3])
function addItem() {
list.push(list.length + 1)
}
return {
list,
addItem
}
}
}
动态组件与组合式API
组合式API与动态组件配合良好:
<template>
<component :is="currentComponent" />
</template>
<script>
import { shallowRef } from 'vue'
import CompA from './CompA.vue'
import CompB from './CompB.vue'
export default {
setup() {
const currentComponent = shallowRef(CompA)
function toggle() {
currentComponent.value =
currentComponent.value === CompA ? CompB : CompA
}
return {
currentComponent,
toggle
}
}
}
</script>
响应式CSS变量
组合式API可以轻松管理CSS变量:
<template>
<div :style="style">内容</div>
</template>
<script>
import { reactive } from 'vue'
export default {
setup() {
const style = reactive({
'--primary-color': '#42b983',
'--text-size': '16px'
})
return {
style
}
}
}
</script>
表单处理模式
组合式API简化了表单处理:
import { reactive } from 'vue'
export default {
setup() {
const form = reactive({
username: '',
password: ''
})
const errors = reactive({})
function validate() {
// 验证逻辑...
}
return {
form,
errors,
validate
}
}
}
路由集成
组合式API与Vue Router深度集成:
import { useRoute, useRouter } from 'vue-router'
export default {
setup() {
const route = useRoute()
const router = useRouter()
function navigate() {
router.push('/new-path')
}
return {
route,
navigate
}
}
}
状态持久化
组合式API便于实现状态持久化:
import { ref, watch } from 'vue'
export default {
setup() {
const count = ref(
Number(localStorage.getItem('count')) || 0
)
watch(count, (newVal) => {
localStorage.setItem('count', newVal)
})
return {
count
}
}
}
动画控制
组合式API提供了更灵活的动画控制:
import { ref } from 'vue'
import { gsap } from 'gsap'
export default {
setup() {
const el = ref(null)
onMounted(() => {
gsap.to(el.value, { x: 100, duration: 1 })
})
return {
el
}
}
}
服务端渲染支持
组合式API在SSR场景下表现良好:
import { ref, onServerPrefetch } from 'vue'
import { fetchData } from './api'
export default {
async setup() {
const data = ref(null)
onServerPrefetch(async () => {
data.value = await fetchData()
})
// 客户端也会执行
if (!data.value) {
data.value = await fetchData()
}
return {
data
}
}
}
调试工具集成
组合式API与Vue DevTools深度集成:
import { reactive } from 'vue'
export default {
setup() {
const state = reactive({
// 这些属性会在DevTools中显示
debugValue: '调试信息',
nested: {
value: '嵌套值'
}
})
return {
state
}
}
}
性能监控
组合式API便于添加性能监控:
import { onMounted } from 'vue'
export default {
setup() {
onMounted(() => {
performance.mark('component-mounted')
// 性能监控逻辑...
})
}
}
错误处理机制
组合式API提供了更好的错误处理方式:
import { onErrorCaptured } from 'vue'
export default {
setup() {
onErrorCaptured((err) => {
console.error('组件错误:', err)
// 返回false阻止错误继续向上传播
return false
})
}
}
响应式转换
组合式API提供了响应式转换工具:
import { toRef, isReactive } from 'vue'
export default {
setup() {
const obj = { a: 1 }
const reactiveObj = reactive(obj)
console.log(isReactive(reactiveObj)) // true
// 将响应式对象的属性转为ref
const aRef = toRef(reactiveObj, 'a')
return {
aRef
}
}
}
组件元信息
组合式API便于管理组件元信息:
import { defineComponent } from 'vue'
export default defineComponent({
name: 'MyComponent',
setup() {
// 组件逻辑...
}
})
响应式工具链
组合式API构建了完整的响应式工具链:
import {
markRaw,
shallowReactive,
shallowReadonly,
customRef
} from 'vue'
export default {
setup() {
// 标记对象为非响应式
const rawObj = markRaw({ shouldNotBeReactive: true })
// 浅层响应式
const shallowState = shallowReactive({ nested: { a: 1 } })
// 自定义ref实现
function useDebouncedRef(value, delay = 200) {
return customRef((track, trigger) => {
let timeout
return {
get() {
track()
return value
},
set(newValue) {
clearTimeout(timeout)
timeout = setTimeout(() => {
value = newValue
trigger()
}, delay)
}
}
})
}
return {
rawObj,
shallowState,
debouncedValue: useDebouncedRef('')
}
}
}
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:编译与运行时的分离设计
下一篇:虚拟DOM的优化策略