Vue3 Composition API 完全指南:从 setup 到 composables

一、为什么需要 Composition API

Options API 在组件变大时,同一个功能的代码被拆分到 data、methods、computed、watch 中,阅读时需要反复跳转。Composition API 让相关逻辑聚合在一起。

二、ref 与 reactive 的选择

Vue
<script setup lang="ts">
import { ref, reactive, computed } from 'vue'

// 基本类型用 ref
const count = ref(0)
const name = ref('')

// 对象类型二者皆可
const user = reactive({ name: 'Tom', age: 18 })
const form = ref({ title: '', content: '' })

// reactive 解构会丢失响应式!
const { name: n1 } = user        // ❌ 丢失
const name2 = toRef(user, 'name') // ✅ 保持
</script>

经验法则:基本类型用 ref,对象用 reactive,需要整体替换时用 ref。

三、watch 与 watchEffect

TypeScript
// watch:明确指定监听源,可拿到新旧值
watch(count, (newVal, oldVal) => {
  console.log(`count: ${oldVal} -> ${newVal}`)
})

// 监听多个
watch([count, name], ([c, n]) => { /* ... */ })

// watchEffect:自动收集依赖,立即执行一次
watchEffect(() => {
  document.title = `${name.value} - ${count.value}`
})

// 停止监听
const stop = watchEffect(() => {})
stop()

四、生命周期映射

| Options API | Composition API | | --- | --- | | beforeCreate | setup() | | created | setup() | | beforeMount | onBeforeMount | | mounted | onMounted | | beforeUpdate | onBeforeUpdate | | updated | onUpdated | | beforeUnmount | onBeforeUnmount | | unmounted | onUnmounted |

五、封装一个 useRequest

TypeScript
// composables/useRequest.ts
import { ref, onMounted } from 'vue'

export function useRequest<T>(url: string) {
  const data = ref<T | null>(null)
  const loading = ref(false)
  const error = ref<Error | null>(null)

  const run = async () => {
    loading.value = true
    error.value = null
    try {
      const res = await fetch(url)
      data.value = await res.json()
    } catch (e) {
      error.value = e as Error
    } finally {
      loading.value = false
    }
  }

  onMounted(run)
  return { data, loading, error, run }
}

使用:

Vue
<script setup lang="ts">
const { data, loading, run } = useRequest<Article[]>('/api/articles')
</script>

<template>
  <div v-if="loading">加载中...</div>
  <ul v-else>
    <li v-for="a in data" :key="a.id">{{ a.title }}</li>
  </ul>
  <button @click="run">刷新</button>
</template>

六、最佳实践

  1. composable 命名统一 useXxx
  2. 一个 composable 只做一件事
  3. 副作用要在 onUnmounted 中清理(定时器、事件监听)
  4. 用 readonly 暴露只读状态,避免外部误改
打赏作者 已有 0 人打赏,共 ¥0.00
我的打赏
前端小李同学
前端小李同学
Lv7 学习会员 原创 2 粉丝 737

Vue / React 双修,喜欢折腾工程化

  • 2文章
  • 3.7万总阅读
  • 1576获赞
  • 737粉丝

评论(2)

设计喵・澳大利亚
用 composable 拆分逻辑之后代码清爽多了,之前一个组件 800 行根本没法维护。
18天前 👍 43 回复 举报
前端小李同学・澳大利亚
对,这也是 Composition API 最大的价值 —— 逻辑复用。
22天前 👍 19 回复 举报