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
相关推荐
凯心39 分钟前
React 中没有 v-model,如何优雅地处理表单输入
前端·vue.js·react.js
x***B4111 小时前
TypeScript项目引用
前端·javascript·typescript
●VON1 小时前
使用 Electron 构建天气桌面小工具:调用公开 API 实现跨平台实时天气查询V1.0.0
前端·javascript·electron·openharmony
码上成长1 小时前
包管理提速:pnpm + Workspace + Changesets 搭建版本体系
前端·前端框架
Bigger1 小时前
Tauri(十九)——实现 macOS 划词监控的完整实践
前端·rust·app
ganshenml2 小时前
【Web】证书(SSL/TLS)与域名之间的关系:完整、通俗、可落地的讲解
前端·网络协议·ssl
这是个栗子3 小时前
npm报错 : 无法加载文件 npm.ps1,因为在此系统上禁止运行脚本
前端·npm·node.js
HIT_Weston4 小时前
44、【Ubuntu】【Gitlab】拉出内网 Web 服务:http.server 分析(一)
前端·ubuntu·gitlab
华仔啊4 小时前
Vue3 如何实现图片懒加载?其实一个 Intersection Observer 就搞定了
前端·vue.js