Vue3的Composition API给我带来的一个很明显的变化,就是业务逻辑终于可以比较自然地从组件里抽出来了。

以前看到一个几百行的组件,经常会发现里面同时混着:

  • 请求接口
  • 分页
  • 搜索
  • Loading
  • 错误处理
  • 表单
  • 弹窗

模板和业务逻辑搅在一起,看着就头大。

Composable可以很好地解决这个问题。

什么是Composable

简单来说,Composable就是一个封装了响应式状态和相关逻辑的函数。

比如:

export function useCounter() {
  const count = ref(0)

  function increment() {
    count.value++
  }

  return {
    count,
    increment
  }
}

组件里:

const {
  count,
  increment
} = useCounter()

这只是一个很简单的例子。

真正有价值的是把复杂的业务逻辑抽出去。

一个真实的列表场景

比如用户列表:

搜索
分页
加载
删除
刷新

如果全部写在页面里:

UserPage.vue
├── search
├── pagination
├── request
├── delete
├── loading
└── error

组件很容易变得臃肿。

可以抽成:

useUsers()

内部负责:

const users = ref<User[]>([])
const loading = ref(false)
const page = ref(1)
const keyword = ref('')

然后:

async function load() {
  loading.value = true

  try {
    users.value = await getUsers({
      page: page.value,
      keyword: keyword.value
    })
  } finally {
    loading.value = false
  }
}

页面只需要调用:

const {
  users,
  loading,
  page,
  keyword,
  load
} = useUsers()

Composable不应该变成"垃圾桶"

这是我觉得很重要的一点。

不能因为有了Composable,就把所有代码都往里塞。

比如:

useEverything.ts

里面包含:

用户
订单
权限
主题
搜索
弹窗
分页

这其实就是把一个大组件变成了一个大的Composable,没什么实质改善。

合理的做法是按职责拆:

useUsers()
usePagination()
useSearch()
usePermission()

一个Composable最好能用一句话说清楚它负责什么。

Composable和工具函数的区别

这两者容易搞混。

工具函数:

function formatDate(date: Date) {
  // ...
}

它不依赖Vue的响应式系统。

而:

function useUsers() {
  const users = ref([])
  // ...
}

它管理响应式状态,还可能依赖Vue的生命周期。

所以不是所有公共代码都该叫useXXX。

如果只是纯函数,就老老实实当工具函数。

Composable可以组合

这是Composition API很漂亮的地方。

比如:

function useUsers() {
  const {
    page,
    pageSize
  } = usePagination()

  const {
    keyword
  } = useSearch()

  // ...

  return {
    page,
    pageSize,
    keyword
  }
}

最终形成:

useUsers
 ├── usePagination
 └── useSearch

每一层都可以单独测试和复用。

生命周期也可以放进去

比如监听窗口大小:

export function useWindowSize() {
  const width = ref(window.innerWidth)

  const update = () => {
    width.value = window.innerWidth
  }

  onMounted(() => {
    window.addEventListener('resize', update)
  })

  onUnmounted(() => {
    window.removeEventListener('resize', update)
  })

  return {
    width
  }
}

页面不用关心事件监听什么时候加什么时候删。

这也是Composable很适合处理的场景。

我对Composable的使用原则

现在我一般遵循几个原则:

第一,先写清楚再抽象。

代码还没稳定的时候就急着抽,后面改起来反而麻烦。

第二,一个Composable一个主要职责。

第三,优先复用真正重复的业务逻辑。

第四,别为了"看起来高级"而写Composable。

有些只有五六行、只用一次的逻辑,留在组件里反而更直观。

最终目的

Composable的目的不是让项目多出几十个useXXX.ts文件。

真正的目的应该是:

让组件负责展示,让Composable负责可复用的业务状态和逻辑。

当一个页面越来越复杂的时候,如果能比较自然地把搜索、分页、请求、权限这些逻辑拆出来,Vue项目的可维护性会提升不少。

这也是我用Vue 3一段时间之后,越来越依赖Composition API的原因。

最后修改:2026 年 09 月 02 日
如果觉得我的文章对你有用,请随意赞赏