vue3 Composable介绍

好的,我们来深入探讨一下 Vue 3 的 Composable

1. 什么是 Composable?

Composable 是 Vue 3 中一个核心的概念和功能,它是可复用的、有状态的逻辑块,用于封装和提取组件中的重复逻辑,让代码更清晰、更易于维护。

你可以把它理解为:专门用来存放 "可以被多个组件复用的业务逻辑" 的函数

2. 为什么需要 Composable?

在 Vue 2 中,我们通常使用 Mixins 来复用逻辑。但 Mixins 存在一些问题:

  • 命名冲突:多个 Mixin 可能会定义相同名称的数据或方法,导致覆盖。
  • 来源不清晰:当一个组件使用了多个 Mixin 后,很难追踪某个数据或方法到底来自哪个 Mixin。
  • 逻辑耦合度高:Mixins 和组件之间是隐式依赖关系,不易于单独测试和维护。

而 Composable 则完美解决了这些问题:

  • 明确的依赖关系:通过函数调用和返回值来显式地传入和获取数据,来源清晰。
  • 无命名冲突:返回的内容通过解构赋值的方式被组件接收,组件可以自己决定命名。
  • 更好的类型推断:对于 TypeScript 非常友好,能提供完整的类型提示。
  • 更易于测试:Composable 本身就是一个函数,可以独立进行单元测试。

3. 如何创建一个 Composable?

创建一个 Composable 非常简单,它就是一个use 开头的函数 (这是一个约定,便于识别),在函数内部可以使用 Vue 的响应式 API(如 ref, reactive, computed, watch 等),并返回需要暴露给组件使用的状态和方法。

示例:创建一个处理计数器逻辑的 Composable

运行

javascript 复制代码
// src/composables/useCounter.js

import { ref, computed, onMounted } from 'vue';

// 定义一个 Composable 函数,通常以 use 开头
export function useCounter(initialValue = 0) {
  // 1. 定义响应式状态
  const count = ref(initialValue);

  // 2. 定义基于状态的计算属性
  const doubleCount = computed(() => count.value * 2);

  // 3. 定义修改状态的方法
  const increment = () => {
    count.value++;
  };

  const decrement = () => {
    count.value--;
  };

  const reset = () => {
    count.value = initialValue;
  };

  // 4. 可以使用生命周期钩子
  onMounted(() => {
    console.log(`计数器已初始化,初始值为: ${count.value}`);
  });

  // 5. 返回需要暴露给组件的内容
  return {
    count,
    doubleCount,
    increment,
    decrement,
    reset
  };
}

4. 如何在组件中使用 Composable?

在组件中,你只需要 导入并调用 这个 Composable 函数,然后通过解构赋值的方式获取其返回的状态和方法即可。

示例:在组件中使用 useCounter

vue 复制代码
<!-- src/components/CounterDisplay.vue -->
<template>
  <div>
    <p>当前计数: {{ count }}</p>
    <p>计数的两倍: {{ doubleCount }}</p>
    <button @click="increment">+1</button>
    <button @click="decrement">-1</button>
    <button @click="reset">重置</button>
  </div>
</template>

<script setup>
import { useCounter } from '@/composables/useCounter';

// 调用 Composable 函数
// 可以传入初始值,如 useCounter(10)
// 通过解构赋值获取返回的状态和方法
const { count, doubleCount, increment, decrement, reset } = useCounter();
</script>

关键点

  • 每次调用 useCounter(),都会创建一个全新的、独立的 状态实例。这意味着如果两个组件都使用了 useCounter,它们的状态是完全隔离的,互不影响。
  • 组件可以根据需要,只解构自己需要的部分。

5. Composable 的最佳实践

  1. 命名规范

    • Composable 函数名必须以 use 开头 ,例如 useCounter, useUser, useCart
    • 文件名通常与函数名一致,例如 useCounter.js
  2. 单一职责原则

    • 一个 Composable 应该只负责一个特定的功能或逻辑。如果一个 Composable 变得过于庞大和复杂,应该考虑将其拆分成多个更小的、职责更单一的 Composable。
  3. 组合与嵌套

    • Composable 可以相互调用。这是一个非常强大的特性,允许你构建复杂的逻辑。

    • 例如,一个 useCart Composable 内部可以调用 useUser Composable 来获取当前用户信息,以便计算购物车商品的会员价格。

    运行

    javascript 复制代码
    // src/composables/useCart.js
    import { useUser } from './useUser';
    
    export function useCart() {
      const { user } = useUser(); // 调用另一个 Composable
    
      // ... 购物车相关逻辑,可以使用 user 的信息
      const cartItems = ref([]);
      
      const calculateDiscountPrice = (item) => {
        if (user.value?.isVIP) {
          return item.price * 0.9; // VIP 9 折
        }
        return item.price;
      };
    
      // ...
      return { cartItems, calculateDiscountPrice };
    }
  4. 避免在 Composable 中访问组件实例

    • 理想情况下,Composable 应该是纯逻辑 的封装,不应该直接依赖于 Vue 组件实例 (this)。
    • 如果确实需要使用组件实例的属性(如 $route, $store),应该通过参数的形式从组件中传递进来,或者使用 Vue 提供的 getCurrentInstance() 函数(但这会降低 Composable 的通用性,应谨慎使用)。

总结

Composable 是 Vue 3 中替代 Mixins更优、更现代的逻辑复用方案。

  • 它通过函数 的形式封装逻辑,通过返回值暴露状态和方法。
  • 它实现了逻辑的复用和隔离,让组件代码更简洁、更清晰。
  • 它遵循明确的依赖关系单一职责原则,极大地提升了代码的可维护性和可测试性。
  • 在 Vue 3 项目中,任何可复用的逻辑都应该被提取为 Composable
相关推荐
子兮曰1 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰1 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万1 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝1 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
三十而立洋1 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁1 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
汉堡大王95272 天前
Jev:不是聊天机器人, 而是一个智能 if 语句
前端·人工智能·后端
梦想很大很大2 天前
从运行事实到回归证据:Workrun 的 Telemetry 与 Evaluation 实践
前端·人工智能·后端
计算机魔术师2 天前
Meta Muse agent 接入 Shopify 的 Shop Pay 实现代理式购物
前端
沙蒿同学2 天前
我用 Go 搭了一条 AI Agent 流水线:从 1 张商品图到一整套淘宝详情页
前端·javascript·后端