Composable跟pinia store的相似度及差异

8 阅读2分钟

Vue 3 Composition API 的核心设计。

实际上,Pinia Store 和 Vue 3 的 Composable 本质上是同一种模式的两种应用场景。 它们在结构和逻辑组织上几乎是镜像对称的。

以下是它们如此相似的原因以及它们之间的细微区别:

1. 结构逻辑的对应关系

如果你对比两者的代码结构,你会发现它们都是基于“状态、派生、动作”这三个支柱:

组成部分Composable (useFileHandler)Pinia Store (fileStore)
状态 (State)ref(), reactive()state: () => ({ ... })
计算属性 (Getters)computed()getters: { ... }
方法 (Actions)function handleUpload() { ... }actions: { handleUpload() { ... } }
暴露 (Exports)return { ... }自动暴露所有定义的属性

2. 为什么感觉像?(核心原因)

因为 Pinia 本身就是为了适配 Composition API 而设计的。

  • Setup Store:Pinia 甚至支持一种 defineStore('id', () => { ... }) 的写法,这种写法看起来和你写的 useFileHandler 完全一模一样
  • 逻辑封装:两者都是为了解决 Vue 2 中 mixins 的痛点,即将“关注点分离”,把散落在各处的功能代码聚合在一起。

3. Composable vs. Pinia 的本质区别

虽然写法像,但它们的生命周期共享范围不同:

Composable (如 useFileHandler)

  • 私有性:每次在组件中调用 const { ... } = useFileHandler(),通常会创建一个全新的、独立的状态实例
  • 生命周期:它的状态通常随着引用它的组件销毁而销毁。
  • 用途:用于逻辑重用。就像一个“逻辑模具”,每次生产出来的东西数据是独立的,但行为(校验、上传)是一致的。

Pinia Store (如 fileStore)

  • 全局性:它是单例的。无论你在 10 个组件里引用多少次,它们指向的都是同一份数据
  • 持久性:除非手动刷新页面,否则数据一直存在于内存中。
  • 用途:用于数据共享。比如你在 InputField 上传了文件,在 Sidebar 里也要看到文件列表,这时必须用 Store。

4. 在你的重构中,它们是如何协作的?

在你的 useFileHandler.js 中,这种相似性体现得淋漓尽致:

JavaScript

export function useFileHandler(isTranslateMode) {
  // 1. 引入 Store(全局共享的数据)
  const fileStore = useFileStore(); 

  // 2. 定义局部逻辑(私有的行为)
  const validateFiles = (files) => { ... };

  // 3. 协调两者
  const upload = (files) => {
    if (validateFiles(files)) {
      fileStore.uploadFiles(files); // 将结果交给全局 Store
    }
  };

  return { upload };
}

总结

你觉得像,是因为 Vue 3 统一了响应式编程的模型

  • Store 是你的“数据库”和“内存银行”。
  • Composable 是你的“业务逻辑层”和“技能插件”。

这种写法让你可以像搭积木一样,在不同的 Hooks 之间传递参数,而不必像 Vue 2 那样去担心 this 指向或命名冲突的问题。