Composable — 封装可复用逻辑

博客里"请求文章列表 + 加载状态 + 错误提示"这套逻辑,首页要用、分类页要用、搜索页也要用。若每个组件复制一遍,改一处就得改多处。Vue3 组合式 API 的答案是 Composable(组合式函数):把可复用逻辑封装成普通函数,谁需要谁调用。本节以 usePosts 为例讲清设计与使用。

什么是 Composable

组合式函数是普通函数,但内部可以使用 ref、computed、watch、生命周期等组合式 API,并返回需要暴露的状态与方法。约定俗成:函数名以 use 开头,如 usePosts、useDebounce,一看名字就知道用途。

第一个 Composable:usePosts

把"请求文章列表"的全部逻辑搬进 composables/usePosts.js:

// composables/usePosts.js
import { ref, onMounted } from 'vue'
import axios from 'axios'
export function usePosts() {
  const posts = ref([])     // 文章列表
  const loading = ref(true) // 是否加载中
  const error = ref('')     // 错误信息
  async function fetchPosts() {
    loading.value = true
    error.value = ''
    try {
      const { data } = await axios.get('/api/posts')
      posts.value = data
    } catch (e) {
      error.value = '文章加载失败'
    } finally {
      loading.value = false
    }
  }
  onMounted(fetchPosts) // 使用时自动请求一次
  return { posts, loading, error, fetchPosts } // 暴露给组件
}

在组件中使用 usePosts

组件里只需几行,就拥有完整的状态与刷新方法:

<!-- HomeView.vue -->
<script setup>
import { usePosts } from '../composables/usePosts'
const { posts, loading, error, fetchPosts } = usePosts() // 拿状态
</script>
<template>
  <p v-if="loading">加载中...</p>
  <p v-else-if="error">{{ error }}</p>
  <ul v-else>
    <li v-for="p in posts" :key="p.id">{{ p.title }}</li>
  </ul>
  <button @click="fetchPosts">刷新列表</button>
</template>

运行后自动加载文章列表,点"刷新列表"可再次请求,逻辑只维护在一处。

带参数的 Composable:useSearchPosts

设计成接收参数,函数就能适配更多场景,搜索逻辑也可以封装:

// composables/useSearchPosts.js
import { ref, watch } from 'vue'
import axios from 'axios'
export function useSearchPosts() {
  const keyword = ref('')  // 组件用 v-model 绑定
  const results = ref([])
  watch(keyword, async (kw) => { // 关键词变化就请求接口
    if (!kw) { results.value = []; return }
    const { data } = await axios.get('/api/search', { params: { q: kw } })
    results.value = data
  })
  return { keyword, results }
}

组件绑定输入框并展示 results 即可,防抖等细节可再封装成 useDebounce。

组合使用与对比 mixins

Composable 能互相调用、层层组合,把复杂逻辑拆成可单独测试的小积木,旧方案 mixins 则会悄悄合并属性、命名冲突难排查。Composable 显式解构、来源清楚、类型推导友好,是 Vue3 推荐做法。

小结:Composable 把带状态的逻辑封装成 useXxx 函数,组件按需调用即可复用,还能相互组合。下一节用 Pinia 管理"收藏文章"这类全局共享数据。

笔记加载中…