更新记录

0.1.0(2026-10-18) 下载此版本

首个公开版本。

新增

  • setup 式 defineStore:defineStore<T>(id, setup): () => T,state 用 Ref、getter 用 ComputedRef、action 用箭头函数;同 id 重复定义幂等并警告
  • 模块级单例注册表:应用级生命周期,跨页面共享状态(Web + Android 双端实测)
  • storeToRefs:模板解构自动解包
  • 实例 API 顶层函数映射:patch(≙ $patch mutator 形态)/ dispose(≙ $dispose)/ getStoreId(≙ $id)
  • Pinia 实例与插件体系:createPinia / setActivePinia / getActivePinia / pinia.use(plugin)(插件返回 void,UTS 约束)
  • 免挂载设计:纯状态管理无需任何挂载代码;插件场景顶层 setActivePinia(createPinia().use(plugin))
  • 平台验证:vdom 模式 Web 与 App-Android(Kotlin 编译链)全用例通过

已知差异

  • 脚本访问 state 需 .value(UTS 无 Proxy);模板经 storeToRefs 解构后自动解包
  • $subscribe / $onAction / $state / $patch 对象形态 / Options 式 defineStore 不支持,详见文档「与标准 Pinia 的差异」

平台兼容性

uni-app x(3.8.6)

Chrome Safari Android iOS 鸿蒙 微信小程序
√ √ √ √ √ √

其他

多语言 暗黑模式 宽屏模式 蒸汽模式
√ √ √ √

中文 | English

梦曦工作室 Logo 微信公众号 二维码

@meng-xi/unix-pinia

为 uni-app x 提供 Pinia 风格的状态管理库(UTS 编写,setup 式,一套 API 多端覆盖)

[![license](https://img.shields.io/github/license/MengXi-Studio/unix-pinia.svg)](./license.md) [![npm](https://img.shields.io/npm/v/@meng-xi/unix-pinia?color=blue)](https://www.npmjs.com/package/@meng-xi/unix-pinia) ![npm](https://img.shields.io/npm/dt/@meng-xi/unix-pinia?color=green)

为什么是 unix-pinia

uni-app x 的 vdom 模式 App 原生端无法使用标准 Pinia(蒸汽模式全平台可用,vdom 模式仅 Web/小程序可用);官方「导出全局 reactive 变量」的裸方案又缺少统一范式——store 命名、跨页面单例、批量更新、订阅,每项都要自己约定。unix-pinia 把 Pinia 的使用习惯完整搬到 UTS:

  • 写过 Pinia? setup 式 defineStore / storeToRefs / createPinia 心智完全对齐,state 用 ref、getter 用 computed、action 用箭头函数,看一眼 API 就能上手;
  • 多端发布? 同一份 UTS 源码,Web 编译为 JS、Android 编译为 Kotlin,由 uni-app x 编译链现场编译,无 JS Bridge;
  • 在意的坑都有实测答案? UTS 无 Proxy 的解包差异、Kotlin 泛型擦除、app.use 原生不可靠——每项都经双端实测并在文档给足替代方案。

设计原则为一比一复刻 Pinia API 面、裁掉平台不可实现项(对标 unix-router 复刻 vue-router):每个裁掉项都有明确原因与替代方案,详见差异对照。

特性

  • setup 式 defineStore - defineStore<T>(id, setup):state 用 Ref、getter 用 ComputedRef、action 用箭头函数,与 Pinia 官方推荐写法一致;返回类型显式 type 标注,编辑器全程提示
  • 免挂载单例 - 模块级注册表保证应用级单例,跨页面共享状态,无需 app.use;纯状态管理零挂载代码
  • 实例 API 顶层函数映射 - patch / dispose / getStoreId 对应 $patch / $dispose / $id(UTS 无 Proxy,无法在 store 对象上挂方法)
  • 跨 store 依赖 - setup 内直接调用对方 useStore,注册表保证单例
  • 插件体系 - pinia.use(plugin) 链式注册,PiniaPluginContext(pinia / store / storeId)对齐标准 Pinia 三字段
  • 幂等与可预测 - 同 id 重复 defineStore 警告并返回既有实例;dispose 后 useStore 重建全新实例
  • 强类型 UTS - 全量显式类型标注;Kotlin 泛型擦除边界(as any)已在库内收敛,业务侧零感知
  • 双端实测 - Web(JS 编译链)与 Android(Kotlin 编译链、真机)全用例通过,双端行为一致

安装

npm——安装后将包内容同步到工程 uni_modules/ux-pinia/(编译器不扫描 node_modules):

pnpm add @meng-xi/unix-pinia
mkdir -p uni_modules && cp -R node_modules/@meng-xi/unix-pinia uni_modules/ux-pinia

插件市场:搜索 ux-pinia 导入 HBuilderX。

packages/core 为标准 uni_modules UTS 插件(utssdk/ 官方目录结构 + interface.uts 对外声明),业务侧从 @/uni_modules/ux-pinia 导入。

快速开始

1. 定义 store(stores/counter.uts)

import type { Ref, ComputedRef } from 'vue'
import { defineStore } from '@/uni_modules/ux-pinia'

export type CounterStore = {
    count: Ref<number>,                   // state:Ref
    doubleCount: ComputedRef<number>,     // getter:ComputedRef
    increment: () => void,                // action:箭头函数(UTS 函数声明不能作值传递)
    reset: () => void                     // $reset 的替代:自定义 reset action
}

export const useCounterStore = defineStore<CounterStore>('counter', (): CounterStore => {
    const count: Ref<number> = ref(0)
    const doubleCount: ComputedRef<number> = computed((): number => count.value * 2)
    const increment = (): void => { count.value++ }
    const reset = (): void => { count.value = 0 }
    return { count, doubleCount, increment, reset } as CounterStore
})

类型导入规范:ComputedRef 编译器不全局注入,必须 import type { ComputedRef } from 'vue';Ref 可注入但建议统一显式导入。

2. 页面使用

import { storeToRefs } from '@/uni_modules/ux-pinia'
import { useCounterStore } from '@/stores/counter.uts'

const store = useCounterStore()                    // 多次调用返回同一实例(跨页面共享)
const { count, doubleCount } = storeToRefs(store)  // 模板解构自动解包

store.count.value++                                // 脚本访问 state:.value(UTS 无 Proxy 不自动解包)

3. 实例 API($-methods 的顶层函数映射)

import { patch, dispose, getStoreId } from '@/uni_modules/ux-pinia'

// ≙ store.$patch(fn):批量修改(仅 mutator 形态)
patch(store, (s: CounterStore): void => { s.count.value = 10 })

const id: string = getStoreId(store)   // ≙ store.$id → 'counter'

dispose(store)                         // ≙ store.$dispose():注销后下次 useStore 重建

4. 跨 store 与插件

// 跨 store 依赖:setup 内直接调用对方 useStore
export const useUserStore = defineStore<UserStore>('user', (): UserStore => {
    const counterStore = useCounterStore()
    const score: Ref<number> = ref(0)
    const addScoreFromCount = (): void => { score.value += counterStore.count.value }
    return { score, addScoreFromCount } as UserStore
})

// 插件(可选;main.uts 顶层登记,P8 实测:原生端 app.use 不可靠,顶层显式登记为唯一可靠形态)
import { createPinia, setActivePinia } from '@/uni_modules/ux-pinia'
setActivePinia(createPinia().use(myPlugin))

运行效果

仓库自带示例工程 packages/playground,进入首页自动运行全部验证用例(响应式矩阵 / 单例跨页面 / patch / 双 store 互调 / 幂等 / dispose 重建),以 [verify] 前缀输出日志并在页面直接显示 pass/fail。示例工程为纯 HBuilderX 工程,用 HBuilderX 打开 packages/playground 即可发行 Web / Android,复验同一组用例。

Android 体验包(云打包产物):下载 APK(vdom 模式,安装后进入各功能页查看 [verify] 结果)

双端实测结论:Web 与 Android 真机(Kotlin 编译链)全部用例通过,双端行为一致;iOS / 鸿蒙代码全端同构,待实测。

交流与支持

想了解设计思路与实现原理(UTS 无 Proxy 的解包差异、Kotlin 泛型擦除红线、$subscribe 裁决过程等)?公众号「梦曦工作室」有系列解析,***:

微信公众号 二维码

导出

  • API:defineStore / storeToRefs / createPinia / setActivePinia / getActivePinia / patch / dispose / getStoreId
  • 类型:Pinia / PiniaPlugin / PiniaPluginContext / Unsubscribe / SubscribeCallback

文档

📖 从入门到精通的完整文档(指南 + API 参考 + 更新日志):

https://mengxi-studio.github.io/unix-pinia/

阅读建议:先看介绍与快速开始,再按 基础用法 → 与标准 Pinia 的差异 深入核心链路,API 细节查 API 参考。

更新日志

📝 https://github.com/MengXi-Studio/unix-pinia/blob/master/packages/docs/src/changelog.md

License

MIT

隐私、权限声明

1. 本插件需要申请的系统权限列表:

无

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

插件不采集任何数据

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

无

许可协议

MIT License

Copyright (c) 2026 MengXi-Studio

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.