Skip to content

Composition API

1. 基础概念

1.1 什么是Composition API

Composition API是Vue3中新增的一种组织组件逻辑的方式,它允许我们按照功能逻辑来组织代码,而不是像Options API那样按照选项类型组织。

1.2 为什么需要Composition API

  • 更好的代码组织
  • 更好的逻辑复用
  • 更好的类型推导
  • 更小的打包体积

2. 核心API

2.1 setup函数

js
import { ref, onMounted } from 'vue'

export default {
  setup(props, context) {
    // 响应式数据
    const count = ref(0)
    
    // 生命周期钩子
    onMounted(() => {
      console.log('组件已挂载')
    })
    
    // 返回给模板使用
    return {
      count
    }
  }
}

2.2 响应式API

ref和reactive

js
import { ref, reactive } from 'vue'

// ref用于基础类型
const count = ref(0)
console.log(count.value) // 访问值需要.value

// reactive用于对象类型
const state = reactive({
  user: {
    name: 'John',
    age: 20
  }
})
console.log(state.user.name) // 直接访问

computed和watch

js
import { ref, computed, watch, watchEffect } from 'vue'

// 计算属性
const count = ref(0)
const doubleCount = computed(() => count.value * 2)

// 监听器
watch(count, (newValue, oldValue) => {
  console.log('count changed:', newValue, oldValue)
})

// 副作用监听
watchEffect(() => {
  console.log('count is:', count.value)
})

3. 生命周期钩子

3.1 组合式API中的生命周期

js
import {
  onBeforeMount,
  onMounted,
  onBeforeUpdate,
  onUpdated,
  onBeforeUnmount,
  onUnmounted
} from 'vue'

export default {
  setup() {
    onBeforeMount(() => {
      // 组件挂载前
    })
    
    onMounted(() => {
      // 组件挂载后
    })
    
    onBeforeUpdate(() => {
      // 组件更新前
    })
    
    onUpdated(() => {
      // 组件更新后
    })
    
    onBeforeUnmount(() => {
      // 组件卸载前
    })
    
    onUnmounted(() => {
      // 组件卸载后
    })
  }
}

4. 组合式函数(Composables)

4.1 创建可复用的组合式函数

js
// useCounter.js
import { ref, computed } from 'vue'

export function useCounter(initialValue = 0) {
  const count = ref(initialValue)
  const doubleCount = computed(() => count.value * 2)
  
  function increment() {
    count.value++
  }
  
  function decrement() {
    count.value--
  }
  
  return {
    count,
    doubleCount,
    increment,
    decrement
  }
}

// 在组件中使用
import { useCounter } from './composables/useCounter'

export default {
  setup() {
    const { count, doubleCount, increment } = useCounter(10)
    return { count, doubleCount, increment }
  }
}

4.2 异步组合式函数

js
// useFetch.js
import { ref } from 'vue'

export function useFetch(url) {
  const data = ref(null)
  const error = ref(null)
  const loading = ref(true)
  
  fetch(url)
    .then(res => res.json())
    .then(json => data.value = json)
    .catch(err => error.value = err)
    .finally(() => loading.value = false)
    
  return { data, error, loading }
}

5. 与TypeScript集成

5.1 类型定义

ts
import { ref, defineComponent } from 'vue'

interface User {
  name: string
  age: number
}

export default defineComponent({
  setup() {
    const user = ref<User>({
      name: 'John',
      age: 20
    })
    
    return { user }
  }
})

5.2 Props类型

ts
import { defineComponent, PropType } from 'vue'

interface Props {
  message: string
  user: User
}

export default defineComponent({
  props: {
    message: String,
    user: Object as PropType<User>
  },
  setup(props: Props) {
    // 使用props
  }
})

6. 最佳实践

6.1 代码组织

js
// 按功能拆分组合式函数
function useUser() {
  const user = ref(null)
  const loading = ref(false)
  
  async function fetchUser(id) {
    loading.value = true
    user.value = await api.getUser(id)
    loading.value = false
  }
  
  return {
    user,
    loading,
    fetchUser
  }
}

// 在组件中组合使用
export default {
  setup() {
    const { user, fetchUser } = useUser()
    const { posts } = usePosts()
    
    return {
      user,
      fetchUser,
      posts
    }
  }
}

6.2 性能优化

  1. 合理使用shallowRefshallowReactive
  2. 使用computed缓存计算结果
  3. 避免不必要的响应式
  4. 及时清理副作用

6.3 调试技巧

  1. 使用Vue Devtools
  2. 合理命名ref和reactive变量
  3. 使用开发环境警告
  4. 性能追踪

7. 注意事项

  1. setup函数中没有this
  2. 避免直接解构props
  3. 响应式数据的局限性
  4. 生命周期钩子的使用时机